From 816ec0b1c33145cde9c6b9b6d24699b3f4df11fe Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 21 Nov 2018 21:14:06 -0800 Subject: [PATCH] refactor(ivy): treate LView as the primary global state (#27282) - rename `LViewData` to `LView` (to be consistent with `TView`) - Remove `getRenderer`, `getRendererFactory`, `getTview`, `getCurrentQueries`, PR Close #27282 --- packages/core/src/debug/debug_node.ts | 4 +- packages/core/src/render3/VIEW_DATA.md | 44 +- packages/core/src/render3/assert.ts | 21 + packages/core/src/render3/bindings.ts | 75 ++ packages/core/src/render3/component.ts | 21 +- packages/core/src/render3/component_ref.ts | 32 +- .../core/src/render3/context_discovery.ts | 107 ++- packages/core/src/render3/definition.ts | 8 +- packages/core/src/render3/di.ts | 71 +- packages/core/src/render3/di_setup.ts | 35 +- packages/core/src/render3/discovery_utils.ts | 44 +- packages/core/src/render3/errors.ts | 20 +- packages/core/src/render3/hooks.ts | 9 +- packages/core/src/render3/i18n.md | 104 +-- packages/core/src/render3/i18n.ts | 37 +- packages/core/src/render3/index.ts | 3 +- packages/core/src/render3/instructions.ts | 644 +++++++++--------- .../core/src/render3/interfaces/container.ts | 18 +- .../core/src/render3/interfaces/context.ts | 6 +- .../core/src/render3/interfaces/definition.ts | 6 +- packages/core/src/render3/interfaces/i18n.ts | 50 +- .../core/src/render3/interfaces/injector.ts | 12 +- packages/core/src/render3/interfaces/node.ts | 12 +- packages/core/src/render3/interfaces/view.ts | 48 +- .../core/src/render3/node_manipulation.ts | 120 ++-- packages/core/src/render3/pipe.ts | 8 +- packages/core/src/render3/players.ts | 6 +- packages/core/src/render3/pure_function.ts | 87 ++- packages/core/src/render3/query.ts | 20 +- packages/core/src/render3/state.ts | 179 +---- .../styling/class_and_style_bindings.ts | 4 +- packages/core/src/render3/styling/util.ts | 20 +- packages/core/src/render3/util.ts | 78 +-- .../src/render3/view_engine_compatibility.ts | 42 +- .../view_engine_compatibility_prebound.ts | 4 +- packages/core/src/render3/view_ref.ts | 39 +- .../core/src/sanitization/sanitization.ts | 38 +- .../bundle.golden_symbols.json | 30 +- .../hello_world/bundle.golden_symbols.json | 19 +- .../hello_world_r2/bundle.golden_symbols.json | 22 +- .../bundling/todo/bundle.golden_symbols.json | 32 +- .../todo_r2/bundle.golden_symbols.json | 35 +- packages/core/test/linker/integration_spec.ts | 6 +- .../test/render3/common_integration_spec.ts | 5 +- packages/core/test/render3/di_spec.ts | 8 +- .../core/test/render3/host_binding_spec.ts | 8 +- packages/core/test/render3/i18n_spec.ts | 6 +- .../core/test/render3/integration_spec.ts | 76 +-- packages/core/test/render3/listeners_spec.ts | 4 +- .../render3/node_selector_matcher_spec.ts | 6 +- packages/core/test/render3/query_spec.ts | 40 +- packages/core/test/render3/render_util.ts | 10 +- .../styling/class_and_style_bindings_spec.ts | 108 ++- packages/core/test/render3/util_spec.ts | 44 +- .../test/render3/view_container_ref_spec.ts | 4 +- .../test/sanitization/sanatization_spec.ts | 4 + 56 files changed, 1217 insertions(+), 1326 deletions(-) create mode 100644 packages/core/src/render3/bindings.ts diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 640a4e4f88..6068e11ef0 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -231,7 +231,7 @@ class DebugNode__POST_R3__ implements DebugNode { // TODO move to discoverable utils const context = loadContext(this.nativeNode as HTMLElement, false) !; if (!context) return []; - const lView = context.lViewData; + const lView = context.lView; const tView = lView[TVIEW]; const tNode = tView.data[context.nodeIndex] as TNode; const providerTokens: any[] = []; @@ -268,7 +268,7 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme get properties(): {[key: string]: any;} { const context = loadContext(this.nativeNode) !; - const lView = context.lViewData; + const lView = context.lView; const tView = lView[TVIEW]; const tNode = tView.data[context.nodeIndex] as TNode; const properties = {}; diff --git a/packages/core/src/render3/VIEW_DATA.md b/packages/core/src/render3/VIEW_DATA.md index a6e8f938ea..560d976d69 100644 --- a/packages/core/src/render3/VIEW_DATA.md +++ b/packages/core/src/render3/VIEW_DATA.md @@ -1,17 +1,17 @@ # View Data Explanation -`LViewData` and `TView.data` are how the Ivy renderer keeps track of the internal data needed to render the template. -`LViewData` is designed so that a single array can contain all of the necessary data for the template rendering in a compact form. -`TView.data` is a corollary to the `LViewData` and contains information which can be shared across the template instances. +`LView` and `TView.data` are how the Ivy renderer keeps track of the internal data needed to render the template. +`LView` is designed so that a single array can contain all of the necessary data for the template rendering in a compact form. +`TView.data` is a corollary to the `LView` and contains information which can be shared across the template instances. -## `LViewData` / `TView.data` layout. +## `LView` / `TView.data` layout. -Both `LViewData` and `TView.data` are arrays whose indices refer to the same item. -For example index `123` may point to a component instance in the `LViewData` but a component type in `TView.data`. +Both `LView` and `TView.data` are arrays whose indices refer to the same item. +For example index `123` may point to a component instance in the `LView` but a component type in `TView.data`. The layout is as such: -| Section | `LViewData` | `TView.data` +| Section | `LView` | `TView.data` | ---------- | ------------------------------------------------------------ | -------------------------------------------------- | `HEADER` | contextual data | mostly `null` | `CONSTS` | DOM, pipe, and local ref instances | @@ -22,7 +22,7 @@ The layout is as such: ## `HEADER` `HEADER` is a fixed array size which contains contextual information about the template. -Mostly information such as parent `LViewData`, `Sanitizer`, `TView`, and many more bits of information needed for template rendering. +Mostly information such as parent `LView`, `Sanitizer`, `TView`, and many more bits of information needed for template rendering. ## `CONSTS` @@ -57,7 +57,7 @@ class MyApp { The above will create following layout: -| Index | `LViewData` | `TView.data` +| Index | `LView` | `TView.data` | ----: | ----------- | ------------ | `HEADER` | `CONSTS` @@ -70,9 +70,9 @@ The above will create following layout: NOTE: - The `10` is not the actual size of `HEADER` but it is left here for simplification. -- `LViewData` contains DOM instances only +- `LView` contains DOM instances only - `TView.data` contains information on relationships such as where the parent is. - You need the `TView.data` information to make sense of the `LViewData` information. + You need the `TView.data` information to make sense of the `LView` information. ## `VARS` @@ -109,7 +109,7 @@ class MyApp { The above will create following layout: -| Index | `LViewData` | `TView.data` +| Index | `LView` | `TView.data` | ----: | ----------- | ------------ | `HEADER` | `CONSTS` @@ -121,7 +121,7 @@ The above will create following layout: | ... | ... | ... NOTE: -- `LViewData` contain DOM instances and previous binding values only +- `LView` contain DOM instances and previous binding values only - `TView.data` contains information on relationships and property labels. @@ -182,7 +182,7 @@ class Tooltip { The above will create the following layout: -| Index | `LViewData` | `TView.data` +| Index | `LView` | `TView.data` | ----: | ----------- | ------------ | `HEADER` | `CONSTS` @@ -256,10 +256,10 @@ This is because at the time of compilation we don't know about all of the inject Injection needs to store three things: - The injection token stored in `TView.data` -- The token factory stored in `LProtoViewData` and subsequently in `LViewData` -- The value for the injection token stored in `LViewData`. (Replacing token factory upon creation). +- The token factory stored in `LProtoViewData` and subsequently in `LView` +- The value for the injection token stored in `LView`. (Replacing token factory upon creation). -To save time when creating `LViewData` we use an array clone operation to copy data from `LProtoViewdata` to `LViewData`. +To save time when creating `LView` we use an array clone operation to copy data from `LProtoViewdata` to `LView`. The `LProtoViewData` is initialized by the `ProvidesFeature`. Injection tokens are sorted into three sections: @@ -321,7 +321,7 @@ class Child { The above will create the following layout: -| Index | `LViewData` | `TView.data` +| Index | `LView` | `TView.data` | ----: | ------------ | ------------- | `HEADER` | `CONSTS` @@ -366,9 +366,9 @@ function isFactory(obj: any): obj is Factory { Pseudo code: 1. Check if bloom filter has the value of the token. (If not exit) 2. Locate the token in the expando honoring `directives`, `providers` and `viewProvider` rules by limiting the search scope. -3. Read the value of `lViewData[index]` at that location. - - if `isFactory(lViewData[index])` then mark it as resolving and invoke it. Replace `lViewData[index]` with the value returned from factory (caching mechanism). - - if `!isFactory(lViewData[index])` then return the cached value as is. +3. Read the value of `lView[index]` at that location. + - if `isFactory(lView[index])` then mark it as resolving and invoke it. Replace `lView[index]` with the value returned from factory (caching mechanism). + - if `!isFactory(lView[index])` then return the cached value as is. # `EXPANDO` and Injecting Special Objects. @@ -437,6 +437,6 @@ function inject(token: any): any { TODO -## Combining `LContainer` with `LViewData` +## Combining `LContainer` with `LView` TODO \ No newline at end of file diff --git a/packages/core/src/render3/assert.ts b/packages/core/src/render3/assert.ts index 2a114899df..3b7bc99403 100644 --- a/packages/core/src/render3/assert.ts +++ b/packages/core/src/render3/assert.ts @@ -7,6 +7,8 @@ */ import {getComponentDef, getNgModuleDef} from './definition'; +import {TNode} from './interfaces/node'; +import {LView} from './interfaces/view'; // The functions in this file verify that the assumptions we are making // about state in an instruction are correct before implementing any logic. @@ -87,3 +89,22 @@ function throwError(msg: string): never { export function assertDomNode(node: any) { assertEqual(node instanceof Node, true, 'The provided value must be an instance of a DOM Node'); } + + +export function assertPreviousIsParent(isParent: boolean) { + assertEqual(isParent, true, 'previousOrParentTNode should be a parent'); +} + +export function assertHasParent(tNode: TNode) { + assertDefined(tNode.parent, 'previousOrParentTNode should have a parent'); +} + +export function assertDataNext(lView: LView, index: number, arr?: any[]) { + if (arr == null) arr = lView; + assertEqual( + arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`); +} + +export function assertDataInRange(arr: any[], index: number) { + assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index'); +} diff --git a/packages/core/src/render3/bindings.ts b/packages/core/src/render3/bindings.ts new file mode 100644 index 0000000000..84a70a6eb4 --- /dev/null +++ b/packages/core/src/render3/bindings.ts @@ -0,0 +1,75 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {devModeEqual} from '../change_detection/change_detection_util'; + +import {assertDataInRange, assertLessThan, assertNotEqual} from './assert'; +import {throwErrorIfNoChangesMode} from './errors'; +import {BINDING_INDEX, LView} from './interfaces/view'; +import {getCheckNoChangesMode, getCreationMode} from './state'; +import {NO_CHANGE} from './tokens'; +import {isDifferent} from './util'; + + + +// TODO(misko): consider inlining +/** Updates binding and returns the value. */ +export function updateBinding(lView: LView, bindingIndex: number, value: any): any { + return lView[bindingIndex] = value; +} + + +/** Gets the current binding value. */ +export function getBinding(lView: LView, bindingIndex: number): any { + ngDevMode && assertDataInRange(lView, lView[bindingIndex]); + ngDevMode && + assertNotEqual(lView[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.'); + return lView[bindingIndex]; +} + +/** Updates binding if changed, then returns whether it was updated. */ +export function bindingUpdated(lView: LView, bindingIndex: number, value: any): boolean { + ngDevMode && assertNotEqual(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); + ngDevMode && + assertLessThan(bindingIndex, lView.length, `Slot should have been initialized to NO_CHANGE`); + + if (lView[bindingIndex] === NO_CHANGE) { + // initial pass + lView[bindingIndex] = value; + } else if (isDifferent(lView[bindingIndex], value)) { + if (ngDevMode && getCheckNoChangesMode()) { + if (!devModeEqual(lView[bindingIndex], value)) { + throwErrorIfNoChangesMode(getCreationMode(), lView[bindingIndex], value); + } + } + lView[bindingIndex] = value; + } else { + return false; + } + return true; +} + +/** Updates 2 bindings if changed, then returns whether either was updated. */ +export function bindingUpdated2(lView: LView, bindingIndex: number, exp1: any, exp2: any): boolean { + const different = bindingUpdated(lView, bindingIndex, exp1); + return bindingUpdated(lView, bindingIndex + 1, exp2) || different; +} + +/** Updates 3 bindings if changed, then returns whether any was updated. */ +export function bindingUpdated3( + lView: LView, bindingIndex: number, exp1: any, exp2: any, exp3: any): boolean { + const different = bindingUpdated2(lView, bindingIndex, exp1, exp2); + return bindingUpdated(lView, bindingIndex + 2, exp3) || different; +} + +/** Updates 4 bindings if changed, then returns whether any was updated. */ +export function bindingUpdated4( + lView: LView, bindingIndex: number, exp1: any, exp2: any, exp3: any, exp4: any): boolean { + const different = bindingUpdated2(lView, bindingIndex, exp1, exp2); + return bindingUpdated2(lView, bindingIndex + 2, exp3, exp4) || different; +} diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index af42ab2980..e16217757b 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -17,14 +17,14 @@ import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; import {publishDefaultGlobalUtils} from './global_utils'; import {queueInitHooks, queueLifecycleHooks} from './hooks'; -import {CLEAN_PROMISE, createLViewData, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, prefillHostVars, queueComponentIndexForCheck, refreshDescendantViews} from './instructions'; +import {CLEAN_PROMISE, createLView, createNodeAtIndex, createTView, getOrCreateTView, initNodeFlags, instantiateRootComponent, locateHostElement, prefillHostVars, queueComponentIndexForCheck, refreshDescendantViews} from './instructions'; import {ComponentDef, ComponentType} from './interfaces/definition'; import {TElementNode, TNodeFlags, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; -import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; +import {CONTEXT, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, RootContext, RootContextFlags, TVIEW} from './interfaces/view'; import {enterView, leaveView, resetComponentState} from './state'; -import {defaultScheduler, getRootView, readPatchedLViewData, stringify} from './util'; +import {defaultScheduler, getRootView, readPatchedLView, stringify} from './util'; @@ -120,7 +120,7 @@ export function renderComponent( const rootContext = createRootContext(opts.scheduler, opts.playerHandler); const renderer = rendererFactory.createRenderer(hostRNode, componentDef); - const rootView: LViewData = createLViewData( + const rootView: LView = createLView( null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, rendererFactory, renderer, undefined, opts.injector || null); @@ -154,12 +154,11 @@ export function renderComponent( * @returns Component view created */ export function createRootComponentView( - rNode: RElement | null, def: ComponentDef, rootView: LViewData, - rendererFactory: RendererFactory3, renderer: Renderer3, - sanitizer?: Sanitizer | null): LViewData { + rNode: RElement | null, def: ComponentDef, rootView: LView, + rendererFactory: RendererFactory3, renderer: Renderer3, sanitizer?: Sanitizer | null): LView { resetComponentState(); const tView = rootView[TVIEW]; - const componentView = createLViewData( + const componentView = createLView( rootView, getOrCreateTView( def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery), @@ -185,8 +184,8 @@ export function createRootComponentView( * renderComponent() and ViewContainerRef.createComponent(). */ export function createRootComponent( - componentView: LViewData, componentDef: ComponentDef, rootView: LViewData, - rootContext: RootContext, hostFeatures: HostFeature[] | null): any { + componentView: LView, componentDef: ComponentDef, rootView: LView, rootContext: RootContext, + hostFeatures: HostFeature[] | null): any { const tView = rootView[TVIEW]; // Create directive instance with factory() and store at next index in viewData const component = instantiateRootComponent(tView, rootView, componentDef); @@ -226,7 +225,7 @@ export function createRootContext( * ``` */ export function LifecycleHooksFeature(component: any, def: ComponentDef): void { - const rootTView = readPatchedLViewData(component) ![TVIEW]; + const rootTView = readPatchedLView(component) ![TVIEW]; const dirIndex = rootTView.data.length - 1; queueInitHooks(dirIndex, def.onInit, def.doCheck, rootTView); diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 5da161ecc4..8b1cd04fd7 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -22,12 +22,12 @@ import {assertComponentType, assertDefined} from './assert'; import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component'; import {getComponentDef} from './definition'; import {NodeInjector} from './di'; -import {createLViewData, createNodeAtIndex, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; +import {createLView, createNodeAtIndex, createTView, createViewNode, elementCreate, locateHostElement, refreshDescendantViews} from './instructions'; import {ComponentDef, RenderFlags} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType} from './interfaces/node'; import {RElement, RendererFactory3, domRendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; -import {HEADER_OFFSET, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view'; +import {HEADER_OFFSET, LView, LViewFlags, RootContext, TVIEW} from './interfaces/view'; import {enterView, leaveView} from './state'; import {defaultScheduler, getTNode} from './util'; import {createElementRef} from './view_engine_compatibility'; @@ -146,12 +146,12 @@ export class ComponentFactory extends viewEngine_ComponentFactory { } // Create the root view. Uses empty TView and ContentTemplate. - const rootView: LViewData = createLViewData( + const rootLView = createLView( null, createTView(-1, null, 1, 0, null, null, null), rootContext, rootFlags, rendererFactory, renderer, sanitizer, rootViewInjector); // rootView is the parent when bootstrapping - const oldView = enterView(rootView, null); + const oldLView = enterView(rootLView, null); let component: T; let tElementNode: TElementNode; @@ -159,14 +159,14 @@ export class ComponentFactory extends viewEngine_ComponentFactory { if (rendererFactory.begin) rendererFactory.begin(); const componentView = createRootComponentView( - hostRNode, this.componentDef, rootView, rendererFactory, renderer); - tElementNode = getTNode(0, rootView) as TElementNode; + hostRNode, this.componentDef, rootLView, rendererFactory, renderer); + tElementNode = getTNode(0, rootLView) as TElementNode; // 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. if (projectableNodes) { let index = 0; - const tView = rootView[TVIEW]; + const tView = rootLView[TVIEW]; const projection: TNode[] = tElementNode.projection = []; for (let i = 0; i < projectableNodes.length; i++) { const nodeList = projectableNodes[i]; @@ -181,7 +181,7 @@ export class ComponentFactory extends viewEngine_ComponentFactory { tView.expandoStartIndex++; tView.blueprint.splice(++index + HEADER_OFFSET, 0, null); tView.data.splice(index + HEADER_OFFSET, 0, null); - rootView.splice(index + HEADER_OFFSET, 0, null); + rootLView.splice(index + HEADER_OFFSET, 0, null); } const tNode = createNodeAtIndex(index, TNodeType.Element, nodeList[j] as RElement, null, null); @@ -196,17 +196,17 @@ export class ComponentFactory extends viewEngine_ComponentFactory { // executed here? // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref component = createRootComponent( - componentView, this.componentDef, rootView, rootContext, [LifecycleHooksFeature]); + componentView, this.componentDef, rootLView, rootContext, [LifecycleHooksFeature]); - refreshDescendantViews(rootView, RenderFlags.Create); + refreshDescendantViews(rootLView, RenderFlags.Create); } finally { - leaveView(oldView, true); + leaveView(oldLView, true); if (rendererFactory.end) rendererFactory.end(); } const componentRef = new ComponentRef( this.componentType, component, - createElementRef(viewEngine_ElementRef, tElementNode, rootView), rootView, tElementNode); + createElementRef(viewEngine_ElementRef, tElementNode, rootLView), rootLView, tElementNode); if (isInternalRootView) { // The host element of the internal root view is attached to the component's host view node @@ -246,16 +246,16 @@ export class ComponentRef extends viewEngine_ComponentRef { constructor( componentType: Type, instance: T, public location: viewEngine_ElementRef, - private _rootView: LViewData, + private _rootLView: LView, private _tNode: TElementNode|TContainerNode|TElementContainerNode) { super(); this.instance = instance; - this.hostView = this.changeDetectorRef = new RootViewRef(_rootView); - this.hostView._tViewNode = createViewNode(-1, _rootView); + this.hostView = this.changeDetectorRef = new RootViewRef(_rootLView); + this.hostView._tViewNode = createViewNode(-1, _rootLView); this.componentType = componentType; } - get injector(): Injector { return new NodeInjector(this._tNode, this._rootView); } + get injector(): Injector { return new NodeInjector(this._tNode, this._rootLView); } destroy(): void { ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index 4a67e09c59..4837c7553e 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -12,7 +12,7 @@ import {EMPTY_ARRAY} from './definition'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {TNode, TNodeFlags} from './interfaces/node'; import {RElement} from './interfaces/renderer'; -import {CONTEXT, HEADER_OFFSET, HOST, LViewData, TVIEW} from './interfaces/view'; +import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view'; import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util'; @@ -23,7 +23,7 @@ import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatched * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched * value will be that of the newly created `LContext`. * - * If the monkey-patched value is the `LViewData` instance then the context value for that + * If the monkey-patched value is the `LView` instance then the context value for that * target will be created and the monkey-patch reference will be updated. Therefore when this * function is called it may mutate the provided element\'s, component\'s or any of the associated * directive\'s monkey-patch values. @@ -39,28 +39,28 @@ import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatched export function getContext(target: any): LContext|null { let mpValue = readPatchedData(target); if (mpValue) { - // only when it's an array is it considered an LViewData instance + // only when it's an array is it considered an LView instance // ... otherwise it's an already constructed LContext instance if (Array.isArray(mpValue)) { - const lViewData: LViewData = mpValue !; + const lView: LView = mpValue !; let nodeIndex: number; let component: any = undefined; let directives: any[]|null|undefined = undefined; if (isComponentInstance(target)) { - nodeIndex = findViaComponent(lViewData, target); + nodeIndex = findViaComponent(lView, target); if (nodeIndex == -1) { throw new Error('The provided component was not found in the application'); } component = target; } else if (isDirectiveInstance(target)) { - nodeIndex = findViaDirective(lViewData, target); + nodeIndex = findViaDirective(lView, target); if (nodeIndex == -1) { throw new Error('The provided directive was not found in the application'); } - directives = getDirectivesAtNodeIndex(nodeIndex, lViewData, false); + directives = getDirectivesAtNodeIndex(nodeIndex, lView, false); } else { - nodeIndex = findViaNativeElement(lViewData, target as RElement); + nodeIndex = findViaNativeElement(lView, target as RElement); if (nodeIndex == -1) { return null; } @@ -70,11 +70,11 @@ export function getContext(target: any): LContext|null { // are expensive. Instead, only the target data (the element, compontent or // directive details) are filled into the context. If called multiple times // with different target values then the missing target data will be filled in. - const native = readElementValue(lViewData[nodeIndex]); + const native = readElementValue(lView[nodeIndex]); const existingCtx = readPatchedData(native); const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ? existingCtx : - createLContext(lViewData, nodeIndex, native); + createLContext(lView, nodeIndex, native); // only when the component has been discovered then update the monkey-patch if (component && context.component === undefined) { @@ -103,23 +103,23 @@ export function getContext(target: any): LContext|null { while (parent = parent.parentNode) { const parentContext = readPatchedData(parent); if (parentContext) { - let lViewData: LViewData|null; + let lView: LView|null; if (Array.isArray(parentContext)) { - lViewData = parentContext as LViewData; + lView = parentContext as LView; } else { - lViewData = parentContext.lViewData; + lView = parentContext.lView; } // the edge of the app was also reached here through another means // (maybe because the DOM was changed manually). - if (!lViewData) { + if (!lView) { return null; } - const index = findViaNativeElement(lViewData, rElement); + const index = findViaNativeElement(lView, rElement); if (index >= 0) { - const native = readElementValue(lViewData[index]); - const context = createLContext(lViewData, index, native); + const native = readElementValue(lView[index]); + const context = createLContext(lView, index, native); attachPatchData(native, context); mpValue = context; break; @@ -133,9 +133,9 @@ export function getContext(target: any): LContext|null { /** * Creates an empty instance of a `LContext` context */ -function createLContext(lViewData: LViewData, nodeIndex: number, native: RElement): LContext { +function createLContext(lView: LView, nodeIndex: number, native: RElement): LContext { return { - lViewData, + lView, nodeIndex, native, component: undefined, @@ -150,20 +150,20 @@ function createLContext(lViewData: LViewData, nodeIndex: number, native: RElemen * @param componentInstance * @returns The component's view */ -export function getComponentViewByInstance(componentInstance: {}): LViewData { - let lViewData = readPatchedData(componentInstance); - let view: LViewData; +export function getComponentViewByInstance(componentInstance: {}): LView { + let lView = readPatchedData(componentInstance); + let view: LView; - if (Array.isArray(lViewData)) { - const nodeIndex = findViaComponent(lViewData, componentInstance); - view = getComponentViewByIndex(nodeIndex, lViewData); - const context = createLContext(lViewData, nodeIndex, view[HOST] as RElement); + if (Array.isArray(lView)) { + const nodeIndex = findViaComponent(lView, componentInstance); + view = getComponentViewByIndex(nodeIndex, lView); + const context = createLContext(lView, nodeIndex, view[HOST] as RElement); context.component = componentInstance; attachPatchData(componentInstance, context); attachPatchData(context.native, context); } else { - const context = lViewData as any as LContext; - view = getComponentViewByIndex(context.nodeIndex, context.lViewData); + const context = lView as any as LContext; + view = getComponentViewByIndex(context.nodeIndex, context.lView); } return view; } @@ -172,7 +172,7 @@ export function getComponentViewByInstance(componentInstance: {}): LViewData { * Assigns the given data to the given target (which could be a component, * directive or DOM node instance) using monkey-patching. */ -export function attachPatchData(target: any, data: LViewData | LContext) { +export function attachPatchData(target: any, data: LView | LContext) { target[MONKEY_PATCH_KEY_NAME] = data; } @@ -185,12 +185,12 @@ export function isDirectiveInstance(instance: any): boolean { } /** - * Locates the element within the given LViewData and returns the matching index + * Locates the element within the given LView and returns the matching index */ -function findViaNativeElement(lViewData: LViewData, target: RElement): number { - let tNode = lViewData[TVIEW].firstChild; +function findViaNativeElement(lView: LView, target: RElement): number { + let tNode = lView[TVIEW].firstChild; while (tNode) { - const native = getNativeByTNode(tNode, lViewData) !; + const native = getNativeByTNode(tNode, lView) !; if (native === target) { return tNode.index; } @@ -215,20 +215,20 @@ function traverseNextElement(tNode: TNode): TNode|null { } /** - * Locates the component within the given LViewData and returns the matching index + * Locates the component within the given LView and returns the matching index */ -function findViaComponent(lViewData: LViewData, componentInstance: {}): number { - const componentIndices = lViewData[TVIEW].components; +function findViaComponent(lView: LView, componentInstance: {}): number { + const componentIndices = lView[TVIEW].components; if (componentIndices) { for (let i = 0; i < componentIndices.length; i++) { const elementComponentIndex = componentIndices[i]; - const componentView = getComponentViewByIndex(elementComponentIndex, lViewData); + const componentView = getComponentViewByIndex(elementComponentIndex, lView); if (componentView[CONTEXT] === componentInstance) { return elementComponentIndex; } } } else { - const rootComponentView = getComponentViewByIndex(HEADER_OFFSET, lViewData); + const rootComponentView = getComponentViewByIndex(HEADER_OFFSET, lView); const rootComponent = rootComponentView[CONTEXT]; if (rootComponent === componentInstance) { // we are dealing with the root element here therefore we know that the @@ -240,20 +240,20 @@ function findViaComponent(lViewData: LViewData, componentInstance: {}): number { } /** - * Locates the directive within the given LViewData and returns the matching index + * Locates the directive within the given LView and returns the matching index */ -function findViaDirective(lViewData: LViewData, directiveInstance: {}): number { +function findViaDirective(lView: LView, directiveInstance: {}): number { // if a directive is monkey patched then it will (by default) - // have a reference to the LViewData of the current view. The + // have a reference to the LView of the current view. The // element bound to the directive being search lives somewhere // in the view data. We loop through the nodes and check their // list of directives for the instance. - let tNode = lViewData[TVIEW].firstChild; + let tNode = lView[TVIEW].firstChild; while (tNode) { const directiveIndexStart = getDirectiveStartIndex(tNode); const directiveIndexEnd = getDirectiveEndIndex(tNode, directiveIndexStart); for (let i = directiveIndexStart; i < directiveIndexEnd; i++) { - if (lViewData[i] === directiveInstance) { + if (lView[i] === directiveInstance) { return tNode.index; } } @@ -267,39 +267,38 @@ function findViaDirective(lViewData: LViewData, directiveInstance: {}): number { * provided list of directive index values. * * @param nodeIndex The node index - * @param lViewData The target view data + * @param lView The target view data * @param includeComponents Whether or not to include components in returned directives */ export function getDirectivesAtNodeIndex( - nodeIndex: number, lViewData: LViewData, includeComponents: boolean): any[]|null { - const tNode = lViewData[TVIEW].data[nodeIndex] as TNode; + nodeIndex: number, lView: LView, includeComponents: boolean): any[]|null { + const tNode = lView[TVIEW].data[nodeIndex] as TNode; let directiveStartIndex = getDirectiveStartIndex(tNode); if (directiveStartIndex == 0) return EMPTY_ARRAY; const directiveEndIndex = getDirectiveEndIndex(tNode, directiveStartIndex); if (!includeComponents && tNode.flags & TNodeFlags.isComponent) directiveStartIndex++; - return lViewData.slice(directiveStartIndex, directiveEndIndex); + return lView.slice(directiveStartIndex, directiveEndIndex); } -export function getComponentAtNodeIndex(nodeIndex: number, lViewData: LViewData): {}|null { - const tNode = lViewData[TVIEW].data[nodeIndex] as TNode; +export function getComponentAtNodeIndex(nodeIndex: number, lView: LView): {}|null { + const tNode = lView[TVIEW].data[nodeIndex] as TNode; let directiveStartIndex = getDirectiveStartIndex(tNode); - return tNode.flags & TNodeFlags.isComponent ? lViewData[directiveStartIndex] : null; + return tNode.flags & TNodeFlags.isComponent ? lView[directiveStartIndex] : null; } /** * Returns a map of local references (local reference name => element or directive instance) that * exist on a given element. */ -export function discoverLocalRefs(lViewData: LViewData, nodeIndex: number): {[key: string]: any}| - null { - const tNode = lViewData[TVIEW].data[nodeIndex] as TNode; +export function discoverLocalRefs(lView: LView, nodeIndex: number): {[key: string]: any}|null { + const tNode = lView[TVIEW].data[nodeIndex] as TNode; if (tNode && tNode.localNames) { const result: {[key: string]: any} = {}; for (let i = 0; i < tNode.localNames.length; i += 2) { const localRefName = tNode.localNames[i]; const directiveIndex = tNode.localNames[i + 1] as number; result[localRefName] = - directiveIndex === -1 ? getNativeByTNode(tNode, lViewData) ! : lViewData[directiveIndex]; + directiveIndex === -1 ? getNativeByTNode(tNode, lView) ! : lView[directiveIndex]; } return result; } diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index f4a29f756e..fb2f9c26b7 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -59,7 +59,7 @@ export function defineComponent(componentDefinition: { /** * The number of nodes, local refs, and pipes in this component template. * - * Used to calculate the length of this component's LViewData array, so we + * Used to calculate the length of this component's LView array, so we * can pre-fill the array and set the binding start index. */ // TODO(kara): remove queries from this count @@ -68,7 +68,7 @@ export function defineComponent(componentDefinition: { /** * The number of bindings in this component template (including pure fn bindings). * - * Used to calculate the length of this component's LViewData array, so we + * Used to calculate the length of this component's LView array, so we * can pre-fill the array and set the host binding start index. */ vars: number; @@ -76,7 +76,7 @@ export function defineComponent(componentDefinition: { /** * The number of host bindings (including pure fn bindings) in this component. * - * Used to calculate the length of the LViewData array for the *parent* component + * Used to calculate the length of the LView array for the *parent* component * of this component. */ hostVars?: number; @@ -589,7 +589,7 @@ export const defineDirective = defineComponent as any as(directiveDefinition: /** * The number of host bindings (including pure fn bindings) in this directive. * - * Used to calculate the length of the LViewData array for the *parent* component + * Used to calculate the length of the LView array for the *parent* component * of this directive. */ hostVars?: number; diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 0c4fe6e4b2..0a824a5edd 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -18,9 +18,9 @@ import {NG_ELEMENT_ID} from './fields'; import {DirectiveDef} from './interfaces/definition'; import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; import {AttributeMarker, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType} from './interfaces/node'; -import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LViewData, TData, TVIEW, TView} from './interfaces/view'; +import {DECLARATION_VIEW, HOST_NODE, INJECTOR, LView, TData, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; -import {_getViewData, getPreviousOrParentTNode, getViewData, setTNodeAndViewData} from './state'; +import {getLView, getPreviousOrParentTNode, setTNodeAndViewData} from './state'; import {getParentInjectorIndex, getParentInjectorView, hasParentInjector, isComponent, stringify} from './util'; /** @@ -130,7 +130,7 @@ export function bloomAdd( * @returns Node injector */ export function getOrCreateNodeInjectorForNode( - tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData): number { + tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LView): number { const existingInjectorIndex = getInjectorIndex(tNode, hostView); if (existingInjectorIndex !== -1) { return existingInjectorIndex; @@ -150,18 +150,18 @@ export function getOrCreateNodeInjectorForNode( const parentLoc = getParentInjectorLocation(tNode, hostView); const parentIndex = getParentInjectorIndex(parentLoc); - const parentView: LViewData = getParentInjectorView(parentLoc, hostView); + const parentLView = getParentInjectorView(parentLoc, hostView); const injectorIndex = tNode.injectorIndex; // If a parent injector can't be found, its location is set to -1. // In that case, we don't need to set up a cumulative bloom if (hasParentInjector(parentLoc)) { - const parentData = parentView[TVIEW].data as any; + const parentData = parentLView[TVIEW].data as any; // Creates a cumulative bloom filter that merges the parent's bloom filter // and its own cumulative bloom (which contains tokens for all ancestors) for (let i = 0; i < 8; i++) { - hostView[injectorIndex + i] = parentView[parentIndex + i] | parentData[parentIndex + i]; + hostView[injectorIndex + i] = parentLView[parentIndex + i] | parentData[parentIndex + i]; } } @@ -174,7 +174,7 @@ function insertBloom(arr: any[], footer: TNode | null): void { } -export function getInjectorIndex(tNode: TNode, hostView: LViewData): number { +export function getInjectorIndex(tNode: TNode, hostView: LView): number { if (tNode.injectorIndex === -1 || // If the injector index is the same as its parent's injector index, then the index has been // copied down from the parent node. No injector has been created yet on this node. @@ -194,7 +194,7 @@ export function getInjectorIndex(tNode: TNode, hostView: LViewData): number { * * Returns a combination of number of `ViewData` we have to go up and index in that `Viewdata` */ -export function getParentInjectorLocation(tNode: TNode, view: LViewData): RelativeInjectorLocation { +export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeInjectorLocation { if (tNode.parent && tNode.parent.injectorIndex !== -1) { return tNode.parent.injectorIndex as any; // ViewOffset is 0, AcrossHostBoundary is 0 } @@ -227,7 +227,7 @@ export function getParentInjectorLocation(tNode: TNode, view: LViewData): Relati * @param token The type or the injection token to be made public */ export function diPublicInInjector( - injectorIndex: number, view: LViewData, token: InjectionToken| Type): void { + injectorIndex: number, view: LView, token: InjectionToken| Type): void { bloomAdd(injectorIndex, view[TVIEW], token); } @@ -292,7 +292,7 @@ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): str * @returns the value from the injector or `null` when not found */ export function getOrCreateInjectable( - tNode: TElementNode | TContainerNode | TElementContainerNode, lViewData: LViewData, + tNode: TElementNode | TContainerNode | TElementContainerNode, lView: LView, token: Type| InjectionToken, flags: InjectFlags = InjectFlags.Default, notFoundValue?: any): T|null { const bloomHash = bloomHashBitOrFactory(token); @@ -300,8 +300,8 @@ export function getOrCreateInjectable( // so just call the factory function to create it. if (typeof bloomHash === 'function') { const savePreviousOrParentTNode = getPreviousOrParentTNode(); - const saveViewData = getViewData(); - setTNodeAndViewData(tNode, lViewData); + const saveLView = getLView(); + setTNodeAndViewData(tNode, lView); try { const value = bloomHash(); if (value == null && !(flags & InjectFlags.Optional)) { @@ -310,7 +310,7 @@ export function getOrCreateInjectable( return value; } } finally { - setTNodeAndViewData(savePreviousOrParentTNode, saveViewData); + setTNodeAndViewData(savePreviousOrParentTNode, saveLView); } } else if (typeof bloomHash == 'number') { // If the token has a bloom hash, then it is a token which could be in NodeInjector. @@ -318,48 +318,48 @@ export function getOrCreateInjectable( // A reference to the previous injector TView that was found while climbing the element injector // tree. This is used to know if viewProviders can be accessed on the current injector. let previousTView: TView|null = null; - let injectorIndex = getInjectorIndex(tNode, lViewData); + let injectorIndex = getInjectorIndex(tNode, lView); let parentLocation: RelativeInjectorLocation = NO_PARENT_INJECTOR; // If we should skip this injector, or if there is no injector on this node, start by searching // the parent injector. if (injectorIndex === -1 || flags & InjectFlags.SkipSelf) { - parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lViewData) : - lViewData[injectorIndex + PARENT_INJECTOR]; + parentLocation = injectorIndex === -1 ? getParentInjectorLocation(tNode, lView) : + lView[injectorIndex + PARENT_INJECTOR]; if (!shouldSearchParent(flags, parentLocation)) { injectorIndex = -1; } else { - previousTView = lViewData[TVIEW]; + previousTView = lView[TVIEW]; injectorIndex = getParentInjectorIndex(parentLocation); - lViewData = getParentInjectorView(parentLocation, lViewData); + lView = getParentInjectorView(parentLocation, lView); } } // Traverse up the injector tree until we find a potential match or until we know there // *isn't* a match. while (injectorIndex !== -1) { - parentLocation = lViewData[injectorIndex + PARENT_INJECTOR]; + parentLocation = lView[injectorIndex + PARENT_INJECTOR]; // Check the current injector. If it matches, see if it contains token. - const tView = lViewData[TVIEW]; + const tView = lView[TVIEW]; if (bloomHasToken(bloomHash, injectorIndex, tView.data)) { // At this point, we have an injector which *may* contain the token, so we step through // the providers and directives associated with the injector's corresponding node to get // the instance. const instance: T|null = - searchTokensOnInjector(injectorIndex, lViewData, token, previousTView); + searchTokensOnInjector(injectorIndex, lView, token, previousTView); if (instance !== NOT_FOUND) { return instance; } } if (shouldSearchParent(flags, parentLocation) && - bloomHasToken(bloomHash, injectorIndex, lViewData)) { + bloomHasToken(bloomHash, injectorIndex, lView)) { // The def wasn't found anywhere on this node, so it was a false positive. // Traverse up the tree and continue searching. previousTView = tView; injectorIndex = getParentInjectorIndex(parentLocation); - lViewData = getParentInjectorView(parentLocation, lViewData); + lView = getParentInjectorView(parentLocation, lView); } else { // If we should not search parent OR If the ancestor bloom filter value does not have the // bit corresponding to the directive we can give up on traversing up to find the specific @@ -375,7 +375,7 @@ export function getOrCreateInjectable( } if ((flags & (InjectFlags.Self | InjectFlags.Host)) === 0) { - const moduleInjector = lViewData[INJECTOR]; + const moduleInjector = lView[INJECTOR]; if (moduleInjector) { return moduleInjector.get(token, notFoundValue, flags & InjectFlags.Optional); } else { @@ -392,7 +392,7 @@ export function getOrCreateInjectable( const NOT_FOUND = {}; function searchTokensOnInjector( - injectorIndex: number, injectorView: LViewData, token: Type| InjectionToken, + injectorIndex: number, injectorView: LView, token: Type| InjectionToken, previousTView: TView | null) { const currentTView = injectorView[TVIEW]; const tNode = currentTView.data[injectorIndex + TNODE] as TNode; @@ -425,15 +425,15 @@ function searchTokensOnInjector( * Searches for the given token among the node's directives and providers. * * @param tNode TNode on which directives are present. - * @param view The view we are currently processing + * @param lView The view we are currently processing * @param token Provider token or type of a directive to look for. * @param canAccessViewProviders Whether view providers should be considered. * @returns Index of a found directive or provider, or null when none found. */ export function locateDirectiveOrProvider( - tNode: TNode, view: LViewData, token: Type| InjectionToken, + tNode: TNode, lView: LView, token: Type| InjectionToken, canAccessViewProviders: boolean): number|null { - const tView = view[TVIEW]; + const tView = lView[TVIEW]; const nodeFlags = tNode.flags; const nodeProviderIndexes = tNode.providerIndexes; const tInjectables = tView.data; @@ -463,7 +463,7 @@ export function locateDirectiveOrProvider( * instantiates the `injectable` and caches the value. */ export function getNodeInjectable( - tData: TData, lData: LViewData, index: number, tNode: TElementNode): any { + tData: TData, lData: LView, index: number, tNode: TElementNode): any { let value = lData[index]; if (isFactory(value)) { const factory: NodeInjectorFactory = value; @@ -477,7 +477,7 @@ export function getNodeInjectable( previousInjectImplementation = setInjectImplementation(factory.injectImpl); } const savePreviousOrParentTNode = getPreviousOrParentTNode(); - const saveViewData = getViewData(); + const saveLView = getLView(); setTNodeAndViewData(tNode, lData); try { value = lData[index] = factory.factory(null, tData, lData, tNode); @@ -485,7 +485,7 @@ export function getNodeInjectable( if (factory.injectImpl) setInjectImplementation(previousInjectImplementation); setIncludeViewProviders(previousIncludeViewProviders); factory.resolving = false; - setTNodeAndViewData(savePreviousOrParentTNode, saveViewData); + setTNodeAndViewData(savePreviousOrParentTNode, saveLView); } } return value; @@ -510,7 +510,7 @@ export function bloomHashBitOrFactory(token: Type| InjectionToken): nu } export function bloomHasToken( - bloomHash: number, injectorIndex: number, injectorView: LViewData | TData) { + bloomHash: number, injectorIndex: number, injectorView: LView | TData) { // Create a mask that targets the specific bit associated with the directive we're looking for. // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding // to bit positions 0 - 31 in a 32 bit integer. @@ -548,21 +548,20 @@ function shouldSearchParent(flags: InjectFlags, parentLocation: RelativeInjector export function injectInjector() { const tNode = getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode; - return new NodeInjector(tNode, getViewData()); + return new NodeInjector(tNode, getLView()); } export class NodeInjector implements Injector { private _injectorIndex: number; constructor( - private _tNode: TElementNode|TContainerNode|TElementContainerNode, - private _lView: LViewData) { + private _tNode: TElementNode|TContainerNode|TElementContainerNode, private _lView: LView) { this._injectorIndex = getOrCreateNodeInjectorForNode(_tNode, _lView); } get(token: any): any { const previousTNode = getPreviousOrParentTNode(); - const previousLView = _getViewData(); + const previousLView = getLView(); setTNodeAndViewData(this._tNode, this._lView); try { return getOrCreateInjectable(this._tNode, this._lView, token); diff --git a/packages/core/src/render3/di_setup.ts b/packages/core/src/render3/di_setup.ts index 06f3bfa7af..9968053e98 100644 --- a/packages/core/src/render3/di_setup.ts +++ b/packages/core/src/render3/di_setup.ts @@ -16,8 +16,8 @@ import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} f import {directiveInject} from './instructions'; import {NodeInjectorFactory} from './interfaces/injector'; import {TContainerNode, TElementContainerNode, TElementNode, TNodeFlags, TNodeProviderIndexes} from './interfaces/node'; -import {LViewData, TData, TVIEW, TView} from './interfaces/view'; -import {getPreviousOrParentTNode, getViewData} from './state'; +import {LView, TData, TVIEW, TView} from './interfaces/view'; +import {getLView, getPreviousOrParentTNode} from './state'; import {isComponentDef} from './util'; @@ -42,8 +42,8 @@ import {isComponentDef} from './util'; */ export function providersResolver( def: DirectiveDef, providers: Provider[], viewProviders: Provider[]): void { - const viewData = getViewData(); - const tView: TView = viewData[TVIEW]; + const lView = getLView(); + const tView: TView = lView[TVIEW]; if (tView.firstTemplatePass) { const isComponent = isComponentDef(def); @@ -71,7 +71,7 @@ function resolveProvider( provider[i], tInjectables, lInjectablesBlueprint, isComponent, isViewProvider); } } else { - const viewData = getViewData(); + const lView = getLView(); let token: any = isTypeProvider(provider) ? provider : resolveForwardRef(provider.provide); let providerFactory: () => any = providerToFactory(provider); @@ -92,8 +92,8 @@ function resolveProvider( diPublicInInjector( getOrCreateNodeInjectorForNode( previousOrParentTNode as TElementNode | TContainerNode | TElementContainerNode, - viewData), - viewData, token); + lView), + lView, token); tInjectables.push(token); previousOrParentTNode.flags += 1 << TNodeFlags.DirectiveStartingIndexShift; if (isViewProvider) { @@ -101,10 +101,10 @@ function resolveProvider( TNodeProviderIndexes.CptViewProvidersCountShifter; } lInjectablesBlueprint.push(factory); - viewData.push(factory); + lView.push(factory); } else { lInjectablesBlueprint[existingFactoryIndex] = factory; - viewData[existingFactoryIndex] = factory; + lView[existingFactoryIndex] = factory; } } else { // Multi provider case: @@ -143,8 +143,8 @@ function resolveProvider( diPublicInInjector( getOrCreateNodeInjectorForNode( previousOrParentTNode as TElementNode | TContainerNode | TElementContainerNode, - viewData), - viewData, token); + lView), + lView, token); const factory = multiFactory( isViewProvider ? multiViewProvidersFactoryResolver : multiProvidersFactoryResolver, lInjectablesBlueprint.length, isViewProvider, isComponent, providerFactory); @@ -158,7 +158,7 @@ function resolveProvider( TNodeProviderIndexes.CptViewProvidersCountShifter; } lInjectablesBlueprint.push(factory); - viewData.push(factory); + lView.push(factory); } else { // Cases 1.b and 2.b multiFactoryAdd( @@ -197,8 +197,7 @@ function indexOf(item: any, arr: any[], begin: number, end: number) { * Use this with `multi` `providers`. */ function multiProvidersFactoryResolver( - this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData, - tNode: TElementNode): any[] { + this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode): any[] { return multiResolve(this.multi !, []); } @@ -208,8 +207,7 @@ function multiProvidersFactoryResolver( * This factory knows how to concatenate itself with the existing `multi` `providers`. */ function multiViewProvidersFactoryResolver( - this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData, - tNode: TElementNode): any[] { + this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode): any[] { const factories = this.multi !; let result: any[]; if (this.providerFactory) { @@ -246,9 +244,8 @@ function multiResolve(factories: Array<() => any>, result: any[]): any[] { * Creates a multi factory. */ function multiFactory( - factoryFn: - (this: NodeInjectorFactory, _: null, tData: TData, lData: LViewData, tNode: TElementNode) => - any, + factoryFn: ( + this: NodeInjectorFactory, _: null, tData: TData, lData: LView, tNode: TElementNode) => any, index: number, isViewProvider: boolean, isComponent: boolean, f: () => any): NodeInjectorFactory { const factory = new NodeInjectorFactory(factoryFn, isViewProvider, directiveInject); diff --git a/packages/core/src/render3/discovery_utils.ts b/packages/core/src/render3/discovery_utils.ts index 306eb36b5b..82128939ad 100644 --- a/packages/core/src/render3/discovery_utils.ts +++ b/packages/core/src/render3/discovery_utils.ts @@ -11,8 +11,8 @@ import {assertDefined} from './assert'; import {discoverLocalRefs, getComponentAtNodeIndex, getContext, getDirectivesAtNodeIndex} from './context_discovery'; import {LContext} from './interfaces/context'; import {TElementNode} from './interfaces/node'; -import {CONTEXT, FLAGS, HOST, LViewData, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view'; -import {readPatchedLViewData, stringify} from './util'; +import {CONTEXT, FLAGS, HOST, LView, LViewFlags, PARENT, RootContext, TVIEW} from './interfaces/view'; +import {readPatchedLView, stringify} from './util'; import {NodeInjector} from './view_engine_compatibility'; @@ -42,7 +42,7 @@ export function getComponent(element: Element): T|null { const context = loadContext(element) !; if (context.component === undefined) { - context.component = getComponentAtNodeIndex(context.nodeIndex, context.lViewData); + context.component = getComponentAtNodeIndex(context.nodeIndex, context.lView); } return context.component as T; @@ -70,7 +70,7 @@ export function getComponent(element: Element): T|null { */ export function getViewComponent(element: Element | {}): T|null { const context = loadContext(element) !; - let lView: LViewData = context.lViewData; + let lView: LView = context.lView; while (lView[PARENT] && lView[HOST] === null) { // As long as lView[HOST] is null we know we are part of sub-template such as `*ngIf` lView = lView[PARENT] !; @@ -86,10 +86,10 @@ export function getViewComponent(element: Element | {}): T|null { * the application where the target is situated. * */ -export function getRootContext(target: LViewData | {}): RootContext { - const lViewData = Array.isArray(target) ? target : loadContext(target) !.lViewData; - const rootLViewData = getRootView(lViewData); - return rootLViewData[CONTEXT] as RootContext; +export function getRootContext(target: LView | {}): RootContext { + const lView = Array.isArray(target) ? target : loadContext(target) !.lView; + const rootLView = getRootView(lView); + return rootLView[CONTEXT] as RootContext; } /** @@ -114,9 +114,9 @@ export function getRootComponents(target: {}): any[] { */ export function getInjector(target: {}): Injector { const context = loadContext(target); - const tNode = context.lViewData[TVIEW].data[context.nodeIndex] as TElementNode; + const tNode = context.lView[TVIEW].data[context.nodeIndex] as TElementNode; - return new NodeInjector(tNode, context.lViewData); + return new NodeInjector(tNode, context.lView); } /** @@ -130,7 +130,7 @@ export function getDirectives(target: {}): Array<{}> { const context = loadContext(target) !; if (context.directives === undefined) { - context.directives = getDirectivesAtNodeIndex(context.nodeIndex, context.lViewData, false); + context.directives = getDirectivesAtNodeIndex(context.nodeIndex, context.lView, false); } return context.directives || []; @@ -154,25 +154,25 @@ export function loadContext(target: {}, throwOnNotFound: boolean = true): LConte } /** - * Retrieve the root view from any component by walking the parent `LViewData` until - * reaching the root `LViewData`. + * Retrieve the root view from any component by walking the parent `LView` until + * reaching the root `LView`. * * @param componentOrView any component or view * */ -export function getRootView(componentOrView: LViewData | {}): LViewData { - let lViewData: LViewData; +export function getRootView(componentOrView: LView | {}): LView { + let lView: LView; if (Array.isArray(componentOrView)) { - ngDevMode && assertDefined(componentOrView, 'lViewData'); - lViewData = componentOrView as LViewData; + ngDevMode && assertDefined(componentOrView, 'lView'); + lView = componentOrView as LView; } else { ngDevMode && assertDefined(componentOrView, 'component'); - lViewData = readPatchedLViewData(componentOrView) !; + lView = readPatchedLView(componentOrView) !; } - while (lViewData && !(lViewData[FLAGS] & LViewFlags.IsRoot)) { - lViewData = lViewData[PARENT] !; + while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { + lView = lView[PARENT] !; } - return lViewData; + return lView; } /** @@ -188,7 +188,7 @@ export function getLocalRefs(target: {}): {[key: string]: any} { const context = loadContext(target) !; if (context.localRefs === undefined) { - context.localRefs = discoverLocalRefs(context.lViewData, context.nodeIndex); + context.localRefs = discoverLocalRefs(context.lView, context.nodeIndex); } return context.localRefs || {}; diff --git a/packages/core/src/render3/errors.ts b/packages/core/src/render3/errors.ts index 9c37210d6e..c390767208 100644 --- a/packages/core/src/render3/errors.ts +++ b/packages/core/src/render3/errors.ts @@ -20,16 +20,14 @@ export function throwMultipleComponentError(tNode: TNode): never { /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */ export function throwErrorIfNoChangesMode( - creationMode: boolean, checkNoChangesMode: boolean, oldValue: any, currValue: any): never|void { - if (checkNoChangesMode) { - let msg = - `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`; - if (creationMode) { - msg += - ` It seems like the view has been created after its parent and its children have been dirty checked.` + - ` Has it been created in a change detection hook ?`; - } - // TODO: include debug context - throw new Error(msg); + creationMode: boolean, oldValue: any, currValue: any): never|void { + let msg = + `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`; + if (creationMode) { + msg += + ` It seems like the view has been created after its parent and its children have been dirty checked.` + + ` Has it been created in a change detection hook ?`; } + // TODO: include debug context + throw new Error(msg); } diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts index cd6a44015f..ad910ca5bb 100644 --- a/packages/core/src/render3/hooks.ts +++ b/packages/core/src/render3/hooks.ts @@ -9,7 +9,7 @@ import {assertEqual} from './assert'; import {DirectiveDef} from './interfaces/definition'; import {TNodeFlags} from './interfaces/node'; -import {FLAGS, HookData, LViewData, LViewFlags, TView} from './interfaces/view'; +import {FLAGS, HookData, LView, LViewFlags, TView} from './interfaces/view'; /** @@ -20,7 +20,7 @@ import {FLAGS, HookData, LViewData, LViewFlags, TView} from './interfaces/view'; * directive index), then saved in the even indices of the initHooks array. The odd indices * hold the hook functions themselves. * - * @param index The index of the directive in LViewData + * @param index The index of the directive in LView * @param hooks The static hooks map on the directive def * @param tView The current TView */ @@ -96,8 +96,7 @@ function queueDestroyHooks(def: DirectiveDef, tView: TView, i: number): voi * * @param currentView The current view */ -export function executeInitHooks( - currentView: LViewData, tView: TView, creationMode: boolean): void { +export function executeInitHooks(currentView: LView, tView: TView, creationMode: boolean): void { if (currentView[FLAGS] & LViewFlags.RunInit) { executeHooks(currentView, tView.initHooks, tView.checkHooks, creationMode); currentView[FLAGS] &= ~LViewFlags.RunInit; @@ -110,7 +109,7 @@ export function executeInitHooks( * @param currentView The current view */ export function executeHooks( - data: LViewData, allHooks: HookData | null, checkHooks: HookData | null, + data: LView, allHooks: HookData | null, checkHooks: HookData | null, creationMode: boolean): void { const hooksToCall = creationMode ? allHooks : checkHooks; if (hooksToCall) { diff --git a/packages/core/src/render3/i18n.md b/packages/core/src/render3/i18n.md index b1f7225e92..4c2ac93109 100644 --- a/packages/core/src/render3/i18n.md +++ b/packages/core/src/render3/i18n.md @@ -166,7 +166,7 @@ const i18nUpdateOpCodes = [ // has changed then execute update OpCodes. // has NOT changed then skip `7` values and start processing next OpCodes. 0b1, 7, - // Concatenate `newValue = 'Hello ' + lViewData[bindIndex-1] + '!';`. + // Concatenate `newValue = 'Hello ' + lView[bindIndex-1] + '!';`. 'Hello ', // accumulate('Hello '); -1, // accumulate(-1); '!', // accumulate('!'); @@ -305,13 +305,13 @@ const tI18n = { create: [ // Processed by `i18nEnd` // Equivalent to: // // Assume expandoIndex = 100; - // const node = lViewData[expandoIndex++] = document.createTextNode(''); - // lViewData[2].insertBefore(node, lViewData[3]); + // const node = lView[expandoIndex++] = document.createTextNode(''); + // lView[2].insertBefore(node, lView[3]); "", 2 << SHIFT_PARENT | 3 << SHIFT_REF | InsertBefore, // Equivalent to: // // Assume expandoIndex = 101; - // const node = lViewData[expandoIndex++] = document.createTextNode('.'); - // lViewData[0].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode('.'); + // lView[0].appendChild(node); '.', 2 << SHIFT_PARENT | AppendChild, ], update: [ // Processed by `i18nApply` @@ -323,7 +323,7 @@ const tI18n = { -1, // accumulate(-1); 'is rendered as: ', // accumulate('is rendered as: '); // Flush the concatenated string to text node at position 100. - 100 << SHIFT_REF | Text, // lViewData[100].textContent = accumulatorFlush(); + 100 << SHIFT_REF | Text, // lView[100].textContent = accumulatorFlush(); ], icus: null, } @@ -369,8 +369,8 @@ const tI18n = { create: [ // Equivalent to: // // Assume expandoIndex = 200; - // const node = lViewData[expandoIndex++] = document.createComment(''); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createComment(''); + // lView[1].appendChild(node); COMMENT_MARKER, '', 1 << SHIFT_PARENT | AppendChild, ], update: [ @@ -380,12 +380,12 @@ const tI18n = { // has NOT changed then skip `2` values and start processing next OpCodes. 0b1, 2, -1, // accumulate(-1); - // Switch ICU: `icuSwitchCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` + // Switch ICU: `icuSwitchCase(lView[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` 200 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch, // NOTE: the bit mask here is the logical OR of all of the masks in the ICU. 0b1, 1, - // Update ICU: `icuUpdateCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` + // Update ICU: `icuUpdateCase(lView[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` // SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);` // SHIFT_ICU: is an index into which ICU is being updated. In our example we only have // one ICU so it is 0-th ICU to update. @@ -401,75 +401,75 @@ const tI18n = { // Case: `0`: `{no emails!}` [ // // assume expandoIndex == 203 - // const node = lViewData[expandoIndex++] = document.createTextNode('no '); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode('no '); + // lView[1].appendChild(node); 'no ', 1 << SHIFT_PARENT | AppendChild, // Equivalent to: // // assume expandoIndex == 204 - // const node = lViewData[expandoIndex++] = document.createElement('b'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createElement('b'); + // lView[1].appendChild(node); ELEMENT_MARKER, 'b', 1 << SHIFT_PARENT | AppendChild, - // const node = lViewData[204]; + // const node = lView[204]; // node.setAttribute('title', 'none'); 204 << SHIFT_REF | Select, 'title', 'none' // // assume expandoIndex == 205 - // const node = lViewData[expandoIndex++] = document.createTextNode('email'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode('email'); + // lView[1].appendChild(node); 'email', 204 << SHIFT_PARENT | AppendChild, ] // Case: `1`: `{one email}` [ // // assume expandoIndex == 203 - // const node = lViewData[expandoIndex++] = document.createTextNode('no '); - // lViewData[1].appendChild(node, lViewData[2]); + // const node = lView[expandoIndex++] = document.createTextNode('no '); + // lView[1].appendChild(node, lView[2]); 'one ', 1 << SHIFT_PARENT | AppendChild, // Equivalent to: // // assume expandoIndex == 204 - // const node = lViewData[expandoIndex++] = document.createElement('b'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createElement('b'); + // lView[1].appendChild(node); ELEMENT_MARKER, 'i', 1 << SHIFT_PARENT | AppendChild, // // assume expandoIndex == 205 - // const node = lViewData[expandoIndex++] = document.createTextNode('email'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode('email'); + // lView[1].appendChild(node); 'email', 204 << SHIFT_PARENT | AppendChild, ] // Case: `"other"`: `{�0� emails}` [ // // assume expandoIndex == 203 - // const node = lViewData[expandoIndex++] = document.createTextNode(''); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode(''); + // lView[1].appendChild(node); '', 1 << SHIFT_PARENT | AppendChild, // Equivalent to: // // assume expandoIndex == 204 - // const node = lViewData[expandoIndex++] = document.createComment('span'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createComment('span'); + // lView[1].appendChild(node); ELEMENT_MARKER, 'span', 1 << SHIFT_PARENT | AppendChild, // // assume expandoIndex == 205 - // const node = lViewData[expandoIndex++] = document.createTextNode('emails'); - // lViewData[1].appendChild(node); + // const node = lView[expandoIndex++] = document.createTextNode('emails'); + // lView[1].appendChild(node); 'emails', 204 << SHIFT_PARENT | AppendChild, ] ], remove: [ // Case: `0`: `{no emails!}` [ - // lViewData[1].remove(lViewData[203]); + // lView[1].remove(lView[203]); 1 << SHIFT_PARENT | 203 << SHIFT_REF | Remove, - // lViewData[1].remove(lViewData[204]); + // lView[1].remove(lView[204]); 1 << SHIFT_PARENT | 204 << SHIFT_REF | Remove, ] // Case: `1`: `{one email}` [ - // lViewData[1].remove(lViewData[203]); + // lView[1].remove(lView[203]); 1 << SHIFT_PARENT | 203 << SHIFT_REF | Remove, - // lViewData[1].remove(lViewData[204]); + // lView[1].remove(lView[204]); 1 << SHIFT_PARENT | 204 << SHIFT_REF | Remove, ] // Case: `"other"`: `{�0� emails}` [ - // lViewData[1].remove(lViewData[203]); + // lView[1].remove(lView[203]); 1 << SHIFT_PARENT | 203 << SHIFT_REF | Remove, - // lViewData[1].remove(lViewData[204]); + // lView[1].remove(lView[204]); 1 << SHIFT_PARENT | 204 << SHIFT_REF | Remove, ] ], @@ -496,9 +496,9 @@ const tI18n = { // has changed then execute update OpCodes. // has NOT changed then skip `4` values and start processing next OpCodes. 0b1, 4, - // Concatenate `newValue = '' + lViewData[bindIndex -1];`. + // Concatenate `newValue = '' + lView[bindIndex -1];`. -1, // accumulate(-1); - // Update attribute: `lViewData[204].setAttribute(204, 'title', 0b1, 2,(null));` + // Update attribute: `lView[204].setAttribute(204, 'title', 0b1, 2,(null));` // NOTE: `null` implies no sanitization. 204 << SHIFT_REF | Attr, 'title', null ] @@ -555,12 +555,12 @@ const tI18n = { // if (first_execution_for_tview) { // ngDevMode && assertEquals(tView.blueprint.length, expandoIndex); // tView.blueprint.push(null); - // ngDevMode && assertEquals(lViewData.length, expandoIndex); - // lViewData.push(node); + // ngDevMode && assertEquals(lView.length, expandoIndex); + // lView.push(node); // } else { - // lViewData[expandoIndex] = node; // save expandoIndex == 100; + // lView[expandoIndex] = node; // save expandoIndex == 100; // } - // lViewData[0].appendChild(node); + // lView[0].appendChild(node); // expandoIndex++; "", 0 << SHIFT_PARENT | AppendChild, ], @@ -636,14 +636,14 @@ const tI18n = { // has NOT changed then skip `2` values and start processing next OpCodes. 0b1, 2, -1, // accumulate(-1) - // Switch ICU: `icuSwitchCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` + // Switch ICU: `icuSwitchCase(lView[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` 200 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch, // NOTE: the bit mask here is the logical OR of all of the masks in the ICU. 0b1, 4, 'You have ', // accumulate('You have '); - // Update ICU: `icuUpdateCase(lViewData[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` + // Update ICU: `icuUpdateCase(lView[200 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` // SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);` // SHIFT_ICU: is an index into which ICU is being updated. In our example we only have // one ICU so it is 0-th ICU to update. @@ -700,7 +700,7 @@ const tI18n = { // has changed then execute update OpCodes. // has NOT changed then skip `1` values and start processing next OpCodes. -1, 2, - -1, // accumulate(lViewData[bindIndex-1]); + -1, // accumulate(lView[bindIndex-1]); 'emails', // accumulate('no emails'); ] ] @@ -789,8 +789,8 @@ const tI18n = { expandoStartIndex: 100, // Assume in this example EXPANDO starts at 100 create: [ // Processed by `i18nEnd` // Equivalent to: - // const node = lViewData[expandoIndex++] = document.createTextNode(''); - // lViewData[0].insertBefore(node, lViewData[3]); + // const node = lView[expandoIndex++] = document.createTextNode(''); + // lView[0].insertBefore(node, lView[3]); "Translated text", 0 << SHIFT_PARENT | AppendChild, ], update: [ ], @@ -799,8 +799,8 @@ const tI18n = { ``` RESOLVE: -- One way we could solve it is by `i18nStart` would store an object in `LViewData` at its position which would implement `RNode` but which would handle the corner case of inserting into a synthetic parent. -- Another way this could be implemented is for `i18nStore` to leave a marker in the `LViewData` which would tell the OpCode processor that it is dealing with a synthetic parent. +- One way we could solve it is by `i18nStart` would store an object in `LView` at its position which would implement `RNode` but which would handle the corner case of inserting into a synthetic parent. +- Another way this could be implemented is for `i18nStore` to leave a marker in the `LView` which would tell the OpCode processor that it is dealing with a synthetic parent. ## Nested ICUs @@ -882,12 +882,12 @@ const tI18n = { // has NOT changed then skip `2` values and start processing next OpCodes. 0b1, 2, -1, // accumulate(-1); - // Switch ICU: `icuSwitchCase(lViewData[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` + // Switch ICU: `icuSwitchCase(lView[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` 100 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch, // NOTE: the bit mask here is the logical OR of all of the masks in the ICU. 0b1, 1, - // Update ICU: `icuUpdateCase(lViewData[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` + // Update ICU: `icuUpdateCase(lView[100 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` // SHIFT_REF: points to: `i18nStart(0, MSG_div, 1);` // SHIFT_ICU: is an index into which ICU is being updated. In our example we only have // one ICU so it is 0-th ICU to update. @@ -925,12 +925,12 @@ const tI18n = { -2, ' ', 100 << SHIFT_REF | Text, // Case: `�0� ` 0b10, 5, -1, - // Switch ICU: `icuSwitchCase(lViewData[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` + // Switch ICU: `icuSwitchCase(lView[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/, accumulatorFlush());` 101 << SHIFT_REF | 0 << SHIFT_ICU | IcuSwitch, // NOTE: the bit mask here is the logical OR of all of the masks int the ICU. 0b10, 1, - // Update ICU: `icuUpdateCase(lViewData[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` + // Update ICU: `icuUpdateCase(lView[101 /*SHIFT_REF*/], 0 /*SHIFT_ICU*/);` 101 << SHIFT_REF | 0 << SHIFT_ICU | IcuUpdate, ], ] diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index b730262609..c2e5941694 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -9,6 +9,7 @@ import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer'; import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; + import {assertDefined, assertEqual, assertGreaterThan} from './assert'; import {allocExpando, createNodeAtIndex, elementAttribute, load, textBinding} from './instructions'; import {LContainer, NATIVE, RENDER_PARENT} from './interfaces/container'; @@ -17,9 +18,9 @@ import {TElementNode, TIcuContainerNode, TNode, TNodeType} from './interfaces/no import {RComment, RElement} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; import {StylingContext} from './interfaces/styling'; -import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, LViewData, TVIEW, TView} from './interfaces/view'; +import {BINDING_INDEX, HEADER_OFFSET, HOST_NODE, LView, RENDERER, TVIEW, TView} from './interfaces/view'; import {appendChild, createTextNode, removeChild} from './node_manipulation'; -import {_getViewData, getIsParent, getPreviousOrParentTNode, getRenderer, getTView, setIsParent, setPreviousOrParentTNode} from './state'; +import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from './state'; import {NO_CHANGE} from './tokens'; import {addAllToArray, getNativeByIndex, getNativeByTNode, getTNode, isLContainer, stringify} from './util'; @@ -334,7 +335,7 @@ const parentIndexStack: number[] = []; * @param subTemplateIndex Optional sub-template index in the `message`. */ export function i18nStart(index: number, message: string, subTemplateIndex?: number): void { - const tView = getTView(); + const tView = getLView()[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); ngDevMode && assertEqual( @@ -350,7 +351,7 @@ export function i18nStart(index: number, message: string, subTemplateIndex?: num function i18nStartFirstPass( tView: TView, index: number, message: string, subTemplateIndex?: number) { i18nIndexStack[++i18nIndexStackPointer] = index; - const viewData = _getViewData(); + const viewData = getLView(); const expandoStartIndex = tView.blueprint.length - HEADER_OFFSET; const previousOrParentTNode = getPreviousOrParentTNode(); const parentTNode = getIsParent() ? getPreviousOrParentTNode() : @@ -457,7 +458,7 @@ function i18nStartFirstPass( function appendI18nNode(tNode: TNode, parentTNode: TNode, previousTNode: TNode | null): TNode { ngDevMode && ngDevMode.rendererMoveNode++; - const viewData = _getViewData(); + const viewData = getLView(); if (!previousTNode) { previousTNode = parentTNode; } @@ -563,7 +564,7 @@ export function i18nPostprocess( * into the render tree, moves the placeholder nodes and removes the deleted nodes. */ export function i18nEnd(): void { - const tView = getTView(); + const tView = getLView()[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); ngDevMode && assertEqual( @@ -577,7 +578,7 @@ export function i18nEnd(): void { * See `i18nEnd` above. */ function i18nEndFirstPass(tView: TView) { - const viewData = _getViewData(); + const viewData = getLView(); ngDevMode && assertEqual( viewData[BINDING_INDEX], viewData[TVIEW].bindingStartIndex, 'i18nEnd should be called before any binding'); @@ -602,8 +603,8 @@ function i18nEndFirstPass(tView: TView) { function readCreateOpCodes( index: number, createOpCodes: I18nMutateOpCodes, expandoStartIndex: number, - viewData: LViewData): number[] { - const renderer = getRenderer(); + viewData: LView): number[] { + const renderer = getLView()[RENDERER]; let currentTNode: TNode|null = null; let previousTNode: TNode|null = null; const visitedPlaceholders: number[] = []; @@ -702,7 +703,7 @@ function readCreateOpCodes( function readUpdateOpCodes( updateOpCodes: I18nUpdateOpCodes, icus: TIcu[] | null, bindingsStartIndex: number, - changeMask: number, viewData: LViewData, bypassCheckBit = false) { + changeMask: number, viewData: LView, bypassCheckBit = false) { let caseCreated = false; for (let i = 0; i < updateOpCodes.length; i++) { // bit code to check if we should apply the next update @@ -786,7 +787,7 @@ function readUpdateOpCodes( } } -function removeNode(index: number, viewData: LViewData) { +function removeNode(index: number, viewData: LView) { const removedPhTNode = getTNode(index, viewData); const removedPhRNode = getNativeByIndex(index, viewData); removeChild(removedPhTNode, removedPhRNode || null, viewData); @@ -839,7 +840,7 @@ export function i18n(index: number, message: string, subTemplateIndex?: number): * @param values */ export function i18nAttributes(index: number, values: string[]): void { - const tView = getTView(); + const tView = getLView()[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); ngDevMode && assertEqual( @@ -906,9 +907,9 @@ export function i18nExp(expression: T | NO_CHANGE): void { */ export function i18nApply(index: number) { if (shiftsCounter) { - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; ngDevMode && assertDefined(tView, `tView should be defined`); - const viewData = _getViewData(); const tI18n = tView.data[index + HEADER_OFFSET]; let updateOpCodes: I18nUpdateOpCodes; let icus: TIcu[]|null = null; @@ -918,8 +919,8 @@ export function i18nApply(index: number) { updateOpCodes = (tI18n as TI18n).update; icus = (tI18n as TI18n).icus; } - const bindingsStartIndex = viewData[BINDING_INDEX] - shiftsCounter - 1; - readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, viewData); + const bindingsStartIndex = lView[BINDING_INDEX] - shiftsCounter - 1; + readUpdateOpCodes(updateOpCodes, icus, bindingsStartIndex, changeMask, lView); // Reset changeMask & maskBit to default for the next update cycle changeMask = 0b0; @@ -1348,10 +1349,10 @@ function icuStart( update: updateCodes }; tIcus.push(tIcu); - const lViewData = _getViewData(); + const lView = getLView(); const worstCaseSize = Math.max(...vars); for (let i = 0; i < worstCaseSize; i++) { - allocExpando(lViewData); + allocExpando(lView); } } diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index db24c29330..6d46469d97 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -78,10 +78,11 @@ export { directiveInject, injectAttribute, + + getCurrentView } from './instructions'; export { - getCurrentView, restoreView, enableBindings, diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 15ecda3a37..50c3c090e8 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -17,10 +17,12 @@ import {StyleSanitizeFn} from '../sanitization/style_sanitizer'; import {Type} from '../type'; import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect'; import {noop} from '../util/noop'; -import {assertDefined, assertEqual, assertLessThan, assertNotEqual} from './assert'; + +import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert'; +import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings'; import {attachPatchData, getComponentViewByInstance} from './context_discovery'; import {diPublicInInjector, getNodeInjectable, getOrCreateInjectable, getOrCreateNodeInjectorForNode, injectAttributeImpl} from './di'; -import {throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors'; +import {throwMultipleComponentError} from './errors'; import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks'; import {ACTIVE_INDEX, LContainer, VIEWS} from './interfaces/container'; import {ComponentDef, ComponentQuery, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, InitialStylingFlags, PipeDefListOrFactory, RenderFlags} from './interfaces/definition'; @@ -32,16 +34,18 @@ import {LQueries} from './interfaces/query'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; import {StylingIndex} from './interfaces/styling'; -import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LViewData, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view'; +import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {appendChild, appendProjectedNode, createTextNode, findComponentView, getLViewChild, getRenderParent, insertView, removeView} from './node_manipulation'; import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher'; -import {assertDataInRange, assertHasParent, assertPreviousIsParent, decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getCleanup, getContextViewData, getCreationMode, getCurrentQueries, getCurrentSanitizer, getElementDepthCount, getFirstTemplatePass, getIsParent, getPreviousOrParentTNode, getRenderer, getRendererFactory, getTView, getTViewCleanup, getViewData, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentQueries, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state'; +import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCreationMode, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state'; import {createStylingContextTemplate, renderStyleAndClassBindings, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings'; import {BoundPlayerFactory} from './styling/player_factory'; import {getStylingContext} from './styling/util'; import {NO_CHANGE} from './tokens'; -import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, isDifferent, loadInternal, readElementValue, readPatchedLViewData, stringify} from './util'; +import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getRootContext, getRootView, getTNode, isComponent, isComponentDef, loadInternal, readElementValue, readPatchedLView, stringify} from './util'; + + /** * A permanent marker promise which signifies that the current CD tree is @@ -60,9 +64,8 @@ const enum BindingDirection { * bindings, refreshes child components. * Note: view hooks are triggered later when leaving the view. */ -export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | null) { - const tView = getTView(); - +export function refreshDescendantViews(lView: LView, rf: RenderFlags | null) { + const tView = lView[TVIEW]; // This needs to be set before children are processed to support recursive components tView.firstTemplatePass = false; setFirstTemplatePass(false); @@ -75,19 +78,19 @@ export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | nu const checkNoChangesMode = getCheckNoChangesMode(); if (!checkNoChangesMode) { - executeInitHooks(viewData, tView, creationMode); + executeInitHooks(lView, tView, creationMode); } - refreshDynamicEmbeddedViews(viewData); + refreshDynamicEmbeddedViews(lView); // Content query results must be refreshed before content hooks are called. refreshContentQueries(tView); if (!checkNoChangesMode) { - executeHooks(viewData, tView.contentHooks, tView.contentCheckHooks, creationMode); + executeHooks(lView, tView.contentHooks, tView.contentCheckHooks, creationMode); } - setHostBindings(tView, viewData); + setHostBindings(tView, lView); } refreshChildComponents(tView.components, rf); @@ -95,7 +98,7 @@ export function refreshDescendantViews(viewData: LViewData, rf: RenderFlags | nu /** Sets the host bindings for the current view. */ -export function setHostBindings(tView: TView, viewData: LViewData): void { +export function setHostBindings(tView: TView, viewData: LView): void { if (tView.expandoInstructions) { let bindingRootIndex = viewData[BINDING_INDEX] = tView.expandoStartIndex; setBindingRoot(bindingRootIndex); @@ -154,11 +157,11 @@ function refreshChildComponents(components: number[] | null, rf: RenderFlags | n } } -export function createLViewData( - parentLView: LViewData | null, tView: TView, context: T | null, flags: LViewFlags, +export function createLView( + parentLView: LView | null, tView: TView, context: T | null, flags: LViewFlags, rendererFactory?: RendererFactory3 | null, renderer?: Renderer3 | null, - sanitizer?: Sanitizer | null, injector?: Injector | null): LViewData { - const lView = tView.blueprint.slice() as LViewData; + sanitizer?: Sanitizer | null, injector?: Injector | null): LView { + const lView = tView.blueprint.slice() as LView; lView[FLAGS] = flags | LViewFlags.CreationMode | LViewFlags.Attached | LViewFlags.RunInit; lView[PARENT] = lView[DECLARATION_VIEW] = parentLView; lView[CONTEXT] = context; @@ -200,19 +203,18 @@ export function createNodeAtIndex( index: number, type: TNodeType, native: RText | RElement | RComment | null, name: string | null, attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode& TIcuContainerNode { - const viewData = getViewData(); - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; const adjustedIndex = index + HEADER_OFFSET; ngDevMode && - assertLessThan(adjustedIndex, viewData.length, `Slot should have been initialized with null`); - viewData[adjustedIndex] = native; + assertLessThan(adjustedIndex, lView.length, `Slot should have been initialized with null`); + lView[adjustedIndex] = native; let tNode = tView.data[adjustedIndex] as TNode; if (tNode == null) { const previousOrParentTNode = getPreviousOrParentTNode(); const isParent = getIsParent(); - tNode = tView.data[adjustedIndex] = - createTNode(viewData, type, adjustedIndex, name, attrs, null); + tNode = tView.data[adjustedIndex] = createTNode(lView, type, adjustedIndex, name, attrs, null); // Now link ourselves into the tree. if (previousOrParentTNode) { @@ -236,7 +238,7 @@ export function createNodeAtIndex( TProjectionNode & TIcuContainerNode; } -export function createViewNode(index: number, view: LViewData) { +export function createViewNode(index: number, view: LView) { // 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) { @@ -255,7 +257,7 @@ export function createViewNode(index: number, view: LViewData) { * i18nApply() or ComponentFactory.create), we need to adjust the blueprint for future * template passes. */ -export function allocExpando(view: LViewData) { +export function allocExpando(view: LView) { const tView = view[TVIEW]; if (tView.firstTemplatePass) { tView.expandoStartIndex++; @@ -283,22 +285,22 @@ export function allocExpando(view: LViewData) { */ export function renderTemplate( hostNode: RElement, templateFn: ComponentTemplate, consts: number, vars: number, context: T, - providedRendererFactory: RendererFactory3, hostView: LViewData | null, + providedRendererFactory: RendererFactory3, hostView: LView | null, directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, - sanitizer?: Sanitizer | null): LViewData { + sanitizer?: Sanitizer | null): LView { if (hostView == null) { resetComponentState(); const renderer = providedRendererFactory.createRenderer(null, null); // We need to create a root view so it's possible to look up the host element through its index - const hostLView = createLViewData( + const hostLView = createLView( null, createTView(-1, null, 1, 0, null, null, null), {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, providedRendererFactory, renderer); enterView(hostLView, null); // SUSPECT! why do we need to enter the View? const componentTView = getOrCreateTView(templateFn, consts, vars, directives || null, pipes || null, null); - hostView = createLViewData( + hostView = createLView( hostLView, componentTView, context, LViewFlags.CheckAlways, providedRendererFactory, renderer, sanitizer); hostView[HOST_NODE] = createNodeAtIndex(0, TNodeType.Element, hostNode, null, null); @@ -314,14 +316,14 @@ export function renderTemplate( * Such lViewNode will then be renderer with renderEmbeddedTemplate() (see below). */ export function createEmbeddedViewAndNode( - tView: TView, context: T, declarationView: LViewData, renderer: Renderer3, - queries: LQueries | null, injectorIndex: number): LViewData { + tView: TView, context: T, declarationView: LView, renderer: Renderer3, queries: LQueries | null, + injectorIndex: number): LView { const _isParent = getIsParent(); const _previousOrParentTNode = getPreviousOrParentTNode(); setIsParent(true); setPreviousOrParentTNode(null !); - const lView = createLViewData(declarationView, tView, context, LViewFlags.CheckAlways); + const lView = createLView(declarationView, tView, context, LViewFlags.CheckAlways); lView[DECLARATION_VIEW] = declarationView; if (queries) { @@ -349,12 +351,12 @@ export function createEmbeddedViewAndNode( * TView for dynamically created views on their host TNode, which only has one instance. */ export function renderEmbeddedTemplate( - viewToRender: LViewData, tView: TView, context: T, rf: RenderFlags) { + viewToRender: LView, tView: TView, context: T, rf: RenderFlags) { const _isParent = getIsParent(); const _previousOrParentTNode = getPreviousOrParentTNode(); setIsParent(true); setPreviousOrParentTNode(null !); - let oldView: LViewData; + let oldView: LView; if (viewToRender[FLAGS] & LViewFlags.IsRoot) { // This is a root view inside the view tree tickRootContext(getRootContext(viewToRender)); @@ -402,7 +404,7 @@ export function nextContext(level: number = 1): T { } function renderComponentOrTemplate( - hostView: LViewData, componentOrContext: T, rf: RenderFlags | null, + hostView: LView, componentOrContext: T, rf: RenderFlags | null, templateFn?: ComponentTemplate) { const rendererFactory = hostView[RENDERER_FACTORY]; const oldView = enterView(hostView, hostView[HOST_NODE]); @@ -432,7 +434,7 @@ function renderComponentOrTemplate( * Dynamically created views do NOT use this configuration (update block and create block are * always run separately). */ -function getRenderFlags(view: LViewData): RenderFlags { +function getRenderFlags(view: LView): RenderFlags { return view[FLAGS] & LViewFlags.CreationMode ? RenderFlags.Create | RenderFlags.Update : RenderFlags.Update; } @@ -477,7 +479,7 @@ export function element( * Creates a logical container for other nodes () backed by a comment node in the DOM. * The instruction must later be followed by `elementContainerEnd()` call. * - * @param index Index of the element in the LViewData array + * @param index Index of the element in the LView array * @param attrs Set of attributes to be used when matching directives. * @param localRefs A set of local reference bindings on the element. * @@ -487,39 +489,40 @@ export function element( */ export function elementContainerStart( index: number, attrs?: TAttributes | null, localRefs?: string[] | null): void { - const viewData = getViewData(); - const tView = getTView(); - const renderer = getRenderer(); + const lView = getLView(); + const tView = lView[TVIEW]; + const renderer = lView[RENDERER]; ngDevMode && assertEqual( - viewData[BINDING_INDEX], tView.bindingStartIndex, + lView[BINDING_INDEX], tView.bindingStartIndex, 'element containers should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateComment++; const native = renderer.createComment(ngDevMode ? 'ng-container' : ''); - ngDevMode && assertDataInRange(index - 1); + ngDevMode && assertDataInRange(lView, index - 1); const tNode = createNodeAtIndex(index, TNodeType.ElementContainer, native, null, attrs || null); - appendChild(native, tNode, viewData); - createDirectivesAndLocals(tView, viewData, localRefs); + appendChild(native, tNode, lView); + createDirectivesAndLocals(tView, lView, localRefs); } /** Mark the end of the . */ export function elementContainerEnd(): void { let previousOrParentTNode = getPreviousOrParentTNode(); - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; if (getIsParent()) { setIsParent(false); } else { - ngDevMode && assertHasParent(); + ngDevMode && assertHasParent(getPreviousOrParentTNode()); previousOrParentTNode = previousOrParentTNode.parent !; setPreviousOrParentTNode(previousOrParentTNode); } ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer); - const currentQueries = getCurrentQueries(); + const currentQueries = lView[QUERIES]; if (currentQueries) { - setCurrentQueries(currentQueries.addNode(previousOrParentTNode as TElementContainerNode)); + lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TElementContainerNode); } queueLifecycleHooks(previousOrParentTNode.flags, tView); @@ -528,7 +531,7 @@ export function elementContainerEnd(): void { /** * Create DOM element. The instruction must later be followed by `elementEnd()` call. * - * @param index Index of the element in the LViewData array + * @param index Index of the element in the LView array * @param name Name of the DOM Node * @param attrs Statically bound set of attributes to be written into the DOM element on creation. * @param localRefs A set of local reference bindings on the element. @@ -539,17 +542,17 @@ export function elementContainerEnd(): void { */ export function elementStart( index: number, name: string, attrs?: TAttributes | null, localRefs?: string[] | null): void { - const viewData = getViewData(); - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; ngDevMode && assertEqual( - viewData[BINDING_INDEX], tView.bindingStartIndex, + lView[BINDING_INDEX], tView.bindingStartIndex, 'elements should be created before any bindings '); ngDevMode && ngDevMode.rendererCreateElement++; const native = elementCreate(name); - ngDevMode && assertDataInRange(index - 1); + ngDevMode && assertDataInRange(lView, index - 1); const tNode = createNodeAtIndex(index, TNodeType.Element, native !, name, attrs || null); @@ -557,14 +560,14 @@ export function elementStart( setUpAttributes(native, attrs); } - appendChild(native, tNode, viewData); - createDirectivesAndLocals(tView, viewData, localRefs); + appendChild(native, tNode, lView); + createDirectivesAndLocals(tView, lView, localRefs); // any immediate children of a component or template container must be pre-emptively // monkey-patched with the component view data so that the element can be inspected // later on using any element discovery utility methods (see `element_discovery.ts`) if (getElementDepthCount() === 0) { - attachPatchData(native, viewData); + attachPatchData(native, lView); } increaseElementDepthCount(); } @@ -577,7 +580,7 @@ export function elementStart( */ export function elementCreate(name: string, overriddenRenderer?: Renderer3): RElement { let native: RElement; - const rendererToUse = overriddenRenderer || getRenderer(); + const rendererToUse = overriddenRenderer || getLView()[RENDERER]; if (isProceduralRenderer(rendererToUse)) { native = rendererToUse.createElement(name, _currentNamespace); @@ -598,7 +601,7 @@ export function elementCreate(name: string, overriddenRenderer?: Renderer3): REl * @param localRefExtractor mapping function that extracts local ref value from TNode */ function createDirectivesAndLocals( - tView: TView, viewData: LViewData, localRefs: string[] | null | undefined, + tView: TView, viewData: LView, localRefs: string[] | null | undefined, localRefExtractor: LocalRefExtractor = getNativeByTNode) { if (!getBindingsEnabled()) return; const previousOrParentTNode = getPreviousOrParentTNode(); @@ -615,10 +618,10 @@ function createDirectivesAndLocals( /** * Takes a list of local names and indices and pushes the resolved local variable values - * to LViewData in the same order as they are loaded in the template with load(). + * to LView in the same order as they are loaded in the template with load(). */ function saveResolvedLocalsInData( - viewData: LViewData, tNode: TNode, localRefExtractor: LocalRefExtractor): void { + viewData: LView, tNode: TNode, localRefExtractor: LocalRefExtractor): void { const localNames = tNode.localNames; if (localNames) { let localIndex = tNode.index + 1; @@ -686,7 +689,7 @@ export function createTView( template: templateFn, viewQuery: viewQuery, node: null !, - data: blueprint.slice(), // Fill in to match HEADER_OFFSET in LViewData + data: blueprint.slice(), // Fill in to match HEADER_OFFSET in LView childIndex: -1, // Children set in addToViewTree(), if any bindingStartIndex: bindingStartIndex, expandoStartIndex: initialViewLength, @@ -709,17 +712,17 @@ export function createTView( }; } -function createViewBlueprint(bindingStartIndex: number, initialViewLength: number): LViewData { +function createViewBlueprint(bindingStartIndex: number, initialViewLength: number): LView { const blueprint = new Array(initialViewLength) .fill(null, 0, bindingStartIndex) - .fill(NO_CHANGE, bindingStartIndex) as LViewData; + .fill(NO_CHANGE, bindingStartIndex) as LView; blueprint[CONTAINER_INDEX] = -1; blueprint[BINDING_INDEX] = bindingStartIndex; return blueprint; } function setUpAttributes(native: RElement, attrs: TAttributes): void { - const renderer = getRenderer(); + const renderer = getLView()[RENDERER]; const isProc = isProceduralRenderer(renderer); let i = 0; @@ -765,7 +768,6 @@ export function createError(text: string, token: any) { */ export function locateHostElement( factory: RendererFactory3, elementOrSelector: RElement | string): RElement|null { - ngDevMode && assertDataInRange(-1); const defaultRenderer = factory.createRenderer(null, null); const rNode = typeof elementOrSelector === 'string' ? (isProceduralRenderer(defaultRenderer) ? @@ -794,29 +796,29 @@ export function locateHostElement( */ export function listener( eventName: string, listenerFn: (e?: any) => any, useCapture = false): void { - const viewData = getViewData(); + const lView = getLView(); const tNode = getPreviousOrParentTNode(); ngDevMode && assertNodeOfPossibleTypes( tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); // add native event listener - applicable to elements only if (tNode.type === TNodeType.Element) { - const native = getNativeByTNode(tNode, viewData) as RElement; + const native = getNativeByTNode(tNode, lView) as RElement; ngDevMode && ngDevMode.rendererAddEventListener++; - const renderer = getRenderer(); + const renderer = lView[RENDERER]; // In order to match current behavior, native DOM event listeners must be added for all // events (including outputs). if (isProceduralRenderer(renderer)) { const cleanupFn = renderer.listen(native, eventName, listenerFn); - storeCleanupFn(viewData, cleanupFn); + storeCleanupFn(lView, cleanupFn); } else { const wrappedListener = wrapListenerWithPreventDefault(listenerFn); native.addEventListener(eventName, wrappedListener, useCapture); - const cleanupInstances = getCleanup(viewData); + const cleanupInstances = getCleanup(lView); cleanupInstances.push(wrappedListener); if (getFirstTemplatePass()) { - getTViewCleanup(viewData).push( + getTViewCleanup(lView).push( eventName, tNode.index, cleanupInstances !.length - 1, useCapture); } } @@ -832,7 +834,7 @@ export function listener( const outputs = tNode.outputs; let outputData: PropertyAliasValue|undefined; if (outputs && (outputData = outputs[eventName])) { - createOutput(viewData, outputData, listenerFn); + createOutput(lView, outputData, listenerFn); } } @@ -840,11 +842,11 @@ export function listener( * Iterates through the outputs associated with a particular event name and subscribes to * each output. */ -function createOutput(viewData: LViewData, outputs: PropertyAliasValue, listener: Function): void { +function createOutput(lView: LView, outputs: PropertyAliasValue, listener: Function): void { for (let i = 0; i < outputs.length; i += 2) { - ngDevMode && assertDataInRange(outputs[i] as number, viewData); - const subscription = viewData[outputs[i] as number][outputs[i + 1]].subscribe(listener); - storeCleanupWithContext(viewData, subscription, subscription.unsubscribe); + ngDevMode && assertDataInRange(lView, outputs[i] as number); + const subscription = lView[outputs[i] as number][outputs[i + 1]].subscribe(listener); + storeCleanupWithContext(lView, subscription, subscription.unsubscribe); } } @@ -855,13 +857,11 @@ function createOutput(viewData: LViewData, outputs: PropertyAliasValue, listener * - Cleanup function * - Index of context we just saved in LView.cleanupInstances */ -export function storeCleanupWithContext( - view: LViewData | null, context: any, cleanupFn: Function): void { - if (!view) view = getViewData(); - getCleanup(view).push(context); +export function storeCleanupWithContext(lView: LView, context: any, cleanupFn: Function): void { + getCleanup(lView).push(context); - if (view[TVIEW].firstTemplatePass) { - getTViewCleanup(view).push(cleanupFn, view[CLEANUP] !.length - 1); + if (lView[TVIEW].firstTemplatePass) { + getTViewCleanup(lView).push(cleanupFn, lView[CLEANUP] !.length - 1); } } @@ -873,7 +873,7 @@ export function storeCleanupWithContext( * * On the first template pass, the index of the cleanup function is saved in TView. */ -export function storeCleanupFn(view: LViewData, cleanupFn: Function): void { +export function storeCleanupFn(view: LView, cleanupFn: Function): void { getCleanup(view).push(cleanupFn); if (view[TVIEW].firstTemplatePass) { @@ -887,17 +887,18 @@ export function elementEnd(): void { if (getIsParent()) { setIsParent(false); } else { - ngDevMode && assertHasParent(); + ngDevMode && assertHasParent(getPreviousOrParentTNode()); previousOrParentTNode = previousOrParentTNode.parent !; setPreviousOrParentTNode(previousOrParentTNode); } ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Element); - const currentQueries = getCurrentQueries(); + const lView = getLView(); + const currentQueries = lView[QUERIES]; if (currentQueries) { - setCurrentQueries(currentQueries.addNode(previousOrParentTNode as TElementNode)); + lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TElementNode); } - queueLifecycleHooks(previousOrParentTNode.flags, getTView()); + queueLifecycleHooks(previousOrParentTNode.flags, getLView()[TVIEW]); decreaseElementDepthCount(); } @@ -913,9 +914,9 @@ export function elementEnd(): void { export function elementAttribute( index: number, name: string, value: any, sanitizer?: SanitizerFn | null): void { if (value !== NO_CHANGE) { - const viewData = getViewData(); - const renderer = getRenderer(); - const element = getNativeByIndex(index, viewData); + const lView = getLView(); + const renderer = lView[RENDERER]; + const element = getNativeByIndex(index, lView); if (value == null) { ngDevMode && ngDevMode.rendererRemoveAttribute++; isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name) : @@ -946,19 +947,19 @@ export function elementAttribute( export function elementProperty( index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null): void { if (value === NO_CHANGE) return; - const viewData = getViewData(); - const element = getNativeByIndex(index, viewData) as RElement | RComment; - const tNode = getTNode(index, viewData); + const lView = getLView(); + const element = getNativeByIndex(index, lView) as RElement | RComment; + const tNode = getTNode(index, lView); const inputData = initializeTNodeInputs(tNode); let dataValue: PropertyAliasValue|undefined; if (inputData && (dataValue = inputData[propName])) { - setInputsForProperty(viewData, dataValue, value); - if (isComponent(tNode)) markDirtyIfOnPush(viewData, index + HEADER_OFFSET); + setInputsForProperty(lView, dataValue, value); + if (isComponent(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET); if (ngDevMode && tNode.type === TNodeType.Element) { - setNgReflectProperties(element as RElement, propName, value); + setNgReflectProperties(lView, element as RElement, propName, value); } } else if (tNode.type === TNodeType.Element) { - const renderer = getRenderer(); + const renderer = lView[RENDERER]; // 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. value = sanitizer != null ? (sanitizer(value) as any) : value; @@ -981,7 +982,7 @@ export function elementProperty( * @returns the TNode object */ export function createTNode( - viewData: LViewData, type: TNodeType, adjustedIndex: number, tagName: string | null, + viewData: LView, type: TNodeType, adjustedIndex: number, tagName: string | null, attrs: TAttributes | null, tViews: TView[] | null): TNode { const previousOrParentTNode = getPreviousOrParentTNode(); ngDevMode && ngDevMode.tNode++; @@ -1019,20 +1020,19 @@ export function createTNode( * Given a list of directive indices and minified input names, sets the * input properties on the corresponding directives. */ -function setInputsForProperty(viewData: LViewData, inputs: PropertyAliasValue, value: any): void { +function setInputsForProperty(lView: LView, inputs: PropertyAliasValue, value: any): void { for (let i = 0; i < inputs.length; i += 2) { - ngDevMode && assertDataInRange(inputs[i] as number, viewData); - viewData[inputs[i] as number][inputs[i + 1]] = value; + ngDevMode && assertDataInRange(lView, inputs[i] as number); + lView[inputs[i] as number][inputs[i + 1]] = value; } } -function setNgReflectProperties(element: RElement, propName: string, value: any) { - const renderer = getRenderer() as ProceduralRenderer3; - const isProcedural = isProceduralRenderer(renderer); +function setNgReflectProperties(lView: LView, element: RElement, propName: string, value: any) { + const renderer = lView[RENDERER]; const attrName = normalizeDebugBindingName(propName); const debugValue = normalizeDebugBindingValue(value); - isProcedural ? renderer.setAttribute(element, attrName, debugValue) : - element.setAttribute(attrName, debugValue); + isProceduralRenderer(renderer) ? renderer.setAttribute(element, attrName, debugValue) : + element.setAttribute(attrName, debugValue); } /** @@ -1044,7 +1044,7 @@ function setNgReflectProperties(element: RElement, propName: string, value: any) */ function generatePropertyAliases( tNodeFlags: TNodeFlags, direction: BindingDirection): PropertyAliases|null { - const tView = getTView(); + const tView = getLView()[TVIEW]; const count = tNodeFlags & TNodeFlags.DirectiveCountMask; let propStore: PropertyAliases|null = null; @@ -1091,7 +1091,7 @@ export function elementClassProp( } const val = (value instanceof BoundPlayerFactory) ? (value as BoundPlayerFactory) : (!!value); - updateElementClassProp(getStylingContext(index, getViewData()), classIndex, val); + updateElementClassProp(getStylingContext(index, getLView()), classIndex, val); } /** @@ -1152,9 +1152,10 @@ export function elementStyling( classDeclarations && classDeclarations.length) { const index = tNode.index - HEADER_OFFSET; if (delegateToClassInput(tNode)) { - const stylingContext = getStylingContext(index, getViewData()); + const lView = getLView(); + const stylingContext = getStylingContext(index, lView); const initialClasses = stylingContext[StylingIndex.PreviousOrCachedMultiClassValue] as string; - setInputsForProperty(getViewData(), tNode.inputs !['class'] !, initialClasses); + setInputsForProperty(lView, tNode.inputs !['class'] !, initialClasses); } elementStylingApply(index); } @@ -1180,12 +1181,12 @@ export function elementStylingApply(index: number, directive?: {}): void { if (directive != undefined) { return hackImplementationOfElementStylingApply(index, directive); // supported in next PR } - const viewData = getViewData(); - const isFirstRender = (viewData[FLAGS] & LViewFlags.CreationMode) !== 0; + const lView = getLView(); + const isFirstRender = (lView[FLAGS] & LViewFlags.CreationMode) !== 0; const totalPlayersQueued = renderStyleAndClassBindings( - getStylingContext(index, viewData), getRenderer(), viewData, isFirstRender); + getStylingContext(index, lView), lView[RENDERER], lView, isFirstRender); if (totalPlayersQueued > 0) { - const rootContext = getRootContext(viewData); + const rootContext = getRootContext(lView); scheduleTick(rootContext, RootContextFlags.FlushPlayers); } } @@ -1231,7 +1232,7 @@ export function elementStyleProp( valueToAdd = value as any as string; } } - updateElementStyleProp(getStylingContext(index, getViewData()), styleIndex, valueToAdd); + updateElementStyleProp(getStylingContext(index, getLView()), styleIndex, valueToAdd); } /** @@ -1262,14 +1263,14 @@ export function elementStylingMap( if (directive != undefined) return hackImplementationOfElementStylingMap( index, classes, styles, directive); // supported in next PR - const viewData = getViewData(); - const tNode = getTNode(index, viewData); - const stylingContext = getStylingContext(index, viewData); + const lView = getLView(); + const tNode = getTNode(index, lView); + const stylingContext = getStylingContext(index, lView); if (delegateToClassInput(tNode) && classes !== NO_CHANGE) { const initialClasses = stylingContext[StylingIndex.PreviousOrCachedMultiClassValue] as string; const classInputVal = (initialClasses.length ? (initialClasses + ' ') : '') + (classes as string); - setInputsForProperty(getViewData(), tNode.inputs !['class'] !, classInputVal); + setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal); } updateStylingMap(stylingContext, classes, styles); } @@ -1291,7 +1292,7 @@ function hackImplementationOfElementStyling( classDeclarations: (string | boolean | InitialStylingFlags)[] | null, styleDeclarations: (string | boolean | InitialStylingFlags)[] | null, styleSanitizer: StyleSanitizeFn | null, directive: {}): void { - const node = getNativeByTNode(getPreviousOrParentTNode(), getViewData()); + const node = getNativeByTNode(getPreviousOrParentTNode(), getLView()); ngDevMode && assertDefined(node, 'expecting parent DOM node'); const hostStylingHackMap: HostStylingHackMap = ((node as any).hostStylingHack || ((node as any).hostStylingHack = new Map())); @@ -1309,11 +1310,12 @@ function hackSquashDeclaration(declarations: (string | boolean | InitialStylingF function hackImplementationOfElementClassProp( index: number, classIndex: number, value: boolean | PlayerFactory, directive: {}): void { - const node = getNativeByIndex(index, getViewData()); + const lView = getLView(); + const node = getNativeByIndex(index, lView); ngDevMode && assertDefined(node, 'could not locate node'); const hostStylingHack: HostStylingHack = (node as any).hostStylingHack.get(directive); const className = hostStylingHack.classDeclarations[classIndex]; - const renderer = getRenderer(); + const renderer = lView[RENDERER]; if (isProceduralRenderer(renderer)) { value ? renderer.addClass(node, className) : renderer.removeClass(node, className); } else { @@ -1350,17 +1352,17 @@ function hackImplementationOfElementStylingMap( * @param value Value to write. This value will be stringified. */ export function text(index: number, value?: any): void { - const viewData = getViewData(); + const lView = getLView(); ngDevMode && assertEqual( - viewData[BINDING_INDEX], getTView().bindingStartIndex, + lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'text nodes should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateTextNode++; - const textNative = createTextNode(value, getRenderer()); + const textNative = createTextNode(value, lView[RENDERER]); const tNode = createNodeAtIndex(index, TNodeType.Element, textNative, null, null); // Text nodes are self closing. setIsParent(false); - appendChild(textNative, tNode, viewData); + appendChild(textNative, tNode, lView); } /** @@ -1372,11 +1374,12 @@ export function text(index: number, value?: any): void { */ export function textBinding(index: number, value: T | NO_CHANGE): void { if (value !== NO_CHANGE) { - ngDevMode && assertDataInRange(index + HEADER_OFFSET); - const element = getNativeByIndex(index, getViewData()) as any as RText; + const lView = getLView(); + ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); + const element = getNativeByIndex(index, lView) as any as RText; ngDevMode && assertDefined(element, 'native element should exist'); ngDevMode && ngDevMode.rendererSetText++; - const renderer = getRenderer(); + const renderer = lView[RENDERER]; isProceduralRenderer(renderer) ? renderer.setValue(element, stringify(value)) : element.textContent = stringify(value); } @@ -1390,7 +1393,7 @@ export function textBinding(index: number, value: T | NO_CHANGE): void { * Instantiate a root component. */ export function instantiateRootComponent( - tView: TView, viewData: LViewData, def: ComponentDef): T { + tView: TView, viewData: LView, def: ComponentDef): T { const rootTNode = getPreviousOrParentTNode(); if (tView.firstTemplatePass) { if (def.providersResolver) def.providersResolver(def); @@ -1407,7 +1410,7 @@ export function instantiateRootComponent( * Resolve the matched directives on a node. */ function resolveDirectives( - tView: TView, viewData: LViewData, directives: DirectiveDef[] | null, tNode: TNode, + tView: TView, viewData: LView, directives: DirectiveDef[] | null, tNode: TNode, localRefs: string[] | null): void { // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in tsickle. ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only'); @@ -1447,7 +1450,7 @@ function resolveDirectives( /** * Instantiate all the directives that were previously resolved on the current node. */ -function instantiateAllDirectives(tView: TView, viewData: LViewData, previousOrParentTNode: TNode) { +function instantiateAllDirectives(tView: TView, viewData: LView, previousOrParentTNode: TNode) { const start = previousOrParentTNode.flags >> TNodeFlags.DirectiveStartingIndexShift; const end = start + (previousOrParentTNode.flags & TNodeFlags.DirectiveCountMask); if (!getFirstTemplatePass() && start < end) { @@ -1489,9 +1492,9 @@ export function generateExpandoInstructionBlock( * after directives are matched (so all directives are saved, then bindings). * Because we are updating the blueprint, we only need to do this once. */ -export function prefillHostVars(tView: TView, viewData: LViewData, totalHostVars: number): void { +export function prefillHostVars(tView: TView, lView: LView, totalHostVars: number): void { for (let i = 0; i < totalHostVars; i++) { - viewData.push(NO_CHANGE); + lView.push(NO_CHANGE); tView.blueprint.push(NO_CHANGE); tView.data.push(null); } @@ -1501,7 +1504,7 @@ export function prefillHostVars(tView: TView, viewData: LViewData, totalHostVars * Process a directive on the current node after its creation. */ function postProcessDirective( - viewData: LViewData, directive: T, def: DirectiveDef, directiveDefIdx: number): void { + viewData: LView, directive: T, def: DirectiveDef, directiveDefIdx: number): void { const previousOrParentTNode = getPreviousOrParentTNode(); postProcessBaseDirective(viewData, previousOrParentTNode, directive, def); ngDevMode && assertDefined(previousOrParentTNode, 'previousOrParentTNode'); @@ -1523,21 +1526,21 @@ function postProcessDirective( * A lighter version of postProcessDirective() that is used for the root component. */ function postProcessBaseDirective( - viewData: LViewData, previousOrParentTNode: TNode, directive: T, def: DirectiveDef): void { - const native = getNativeByTNode(previousOrParentTNode, viewData); + lView: LView, previousOrParentTNode: TNode, directive: T, def: DirectiveDef): void { + const native = getNativeByTNode(previousOrParentTNode, lView); ngDevMode && assertEqual( - viewData[BINDING_INDEX], getTView().bindingStartIndex, + lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'directives should be created before any bindings'); - ngDevMode && assertPreviousIsParent(); + ngDevMode && assertPreviousIsParent(getIsParent()); if (def.hostBindings) { def.hostBindings(RenderFlags.Create, directive, previousOrParentTNode.index); } - attachPatchData(directive, viewData); + attachPatchData(directive, lView); if (native) { - attachPatchData(native, viewData); + attachPatchData(native, lView); } // TODO(misko): setUpAttributes should be a feature for better treeshakability. @@ -1552,7 +1555,7 @@ function postProcessBaseDirective( * Matches the current node against all available selectors. * If a component is matched (at most one), it is returned in first position in the array. */ -function findDirectiveMatches(tView: TView, viewData: LViewData, tNode: TNode): DirectiveDef[]| +function findDirectiveMatches(tView: TView, viewData: LView, tNode: TNode): DirectiveDef[]| null { ngDevMode && assertEqual(getFirstTemplatePass(), true, 'should run on first template pass only'); const registry = tView.directiveRegistry; @@ -1587,7 +1590,7 @@ function findDirectiveMatches(tView: TView, viewData: LViewData, tNode: TNode): export function queueComponentIndexForCheck(previousOrParentTNode: TNode): void { ngDevMode && assertEqual(getFirstTemplatePass(), true, 'Should only be called in first template pass.'); - const tView = getTView(); + const tView = getLView()[TVIEW]; (tView.components || (tView.components = [])).push(previousOrParentTNode.index); } @@ -1652,7 +1655,7 @@ export function initNodeFlags(tNode: TNode, index: number, numberOfDirectives: n } function baseResolveDirective( - tView: TView, viewData: LViewData, def: DirectiveDef, + tView: TView, viewData: LView, def: DirectiveDef, directiveFactory: (t: Type| null) => any) { tView.data.push(def); const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); @@ -1663,27 +1666,27 @@ function baseResolveDirective( } function addComponentLogic( - viewData: LViewData, previousOrParentTNode: TNode, def: ComponentDef): void { - const native = getNativeByTNode(previousOrParentTNode, viewData); + lView: LView, previousOrParentTNode: TNode, def: ComponentDef): void { + const native = getNativeByTNode(previousOrParentTNode, lView); const tView = getOrCreateTView( def.template, def.consts, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery); // Only component views should be added to the view tree directly. Embedded views are // accessed through their containers because they may be removed / re-added later. - const rendererFactory = getRendererFactory(); + const rendererFactory = lView[RENDERER_FACTORY]; const componentView = addToViewTree( - viewData, previousOrParentTNode.index as number, - createLViewData( - getViewData(), tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, - rendererFactory, getRendererFactory().createRenderer(native as RElement, def))); + lView, previousOrParentTNode.index as number, + createLView( + lView, tView, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, + rendererFactory, lView[RENDERER_FACTORY].createRenderer(native as RElement, def))); componentView[HOST_NODE] = previousOrParentTNode as TElementNode; // Component view will always be created before any injected LContainers, // so this is a regular element, wrap it with the component view - componentView[HOST] = viewData[previousOrParentTNode.index]; - viewData[previousOrParentTNode.index] = componentView; + componentView[HOST] = lView[previousOrParentTNode.index]; + lView[previousOrParentTNode.index] = componentView; if (getFirstTemplatePass()) { queueComponentIndexForCheck(previousOrParentTNode); @@ -1773,7 +1776,7 @@ function generateInitialInputs( */ export function createLContainer( hostNative: RElement | RComment, - hostTNode: TElementNode | TContainerNode | TElementContainerNode, currentView: LViewData, + hostTNode: TElementNode | TContainerNode | TElementContainerNode, currentView: LView, native: RComment, isForViewContainerRef?: boolean): LContainer { return [ isForViewContainerRef ? -1 : 0, // active index @@ -1808,8 +1811,8 @@ export function template( index: number, templateFn: ComponentTemplate| null, consts: number, vars: number, tagName?: string | null, attrs?: TAttributes | null, localRefs?: string[] | null, localRefExtractor?: LocalRefExtractor) { - const viewData = getViewData(); - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; // TODO: consider a separate node type for templates const tNode = containerInternal(index, tagName || null, attrs || null); @@ -1818,11 +1821,11 @@ export function template( -1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null); } - createDirectivesAndLocals(tView, viewData, localRefs, localRefExtractor); - const currentQueries = getCurrentQueries(); + createDirectivesAndLocals(tView, lView, localRefs, localRefExtractor); + const currentQueries = lView[QUERIES]; const previousOrParentTNode = getPreviousOrParentTNode(); if (currentQueries) { - setCurrentQueries(currentQueries.addNode(previousOrParentTNode as TContainerNode)); + lView[QUERIES] = currentQueries.addNode(previousOrParentTNode as TContainerNode); } queueLifecycleHooks(tNode.flags, tView); setIsParent(false); @@ -1845,25 +1848,25 @@ export function container(index: number): void { function containerInternal( index: number, tagName: string | null, attrs: TAttributes | null): TNode { - const viewData = getViewData(); + const lView = getLView(); ngDevMode && assertEqual( - viewData[BINDING_INDEX], getTView().bindingStartIndex, + lView[BINDING_INDEX], lView[TVIEW].bindingStartIndex, 'container nodes should be created before any bindings'); const adjustedIndex = index + HEADER_OFFSET; - const comment = getRenderer().createComment(ngDevMode ? 'container' : ''); + const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : ''); ngDevMode && ngDevMode.rendererCreateComment++; const tNode = createNodeAtIndex(index, TNodeType.Container, comment, tagName, attrs); - const lContainer = viewData[adjustedIndex] = - createLContainer(viewData[adjustedIndex], tNode, viewData, comment); + const lContainer = lView[adjustedIndex] = + createLContainer(lView[adjustedIndex], tNode, lView, comment); - appendChild(comment, tNode, viewData); + appendChild(comment, tNode, lView); // Containers are added to the current view tree instead of their embedded views // because views can be removed and re-inserted. - addToViewTree(viewData, index + HEADER_OFFSET, lContainer); + addToViewTree(lView, index + HEADER_OFFSET, lContainer); - const currentQueries = getCurrentQueries(); + const currentQueries = lView[QUERIES]; if (currentQueries) { // prepare place for matching nodes from views inserted into a given container lContainer[QUERIES] = currentQueries.container(); @@ -1879,20 +1882,20 @@ function containerInternal( * @param index The index of the container in the data array */ export function containerRefreshStart(index: number): void { - const viewData = getViewData(); - const tView = getTView(); - let previousOrParentTNode = loadInternal(index, tView.data) as TNode; + const lView = getLView(); + const tView = lView[TVIEW]; + let previousOrParentTNode = loadInternal(tView.data, index) as TNode; setPreviousOrParentTNode(previousOrParentTNode); ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container); setIsParent(true); - viewData[index + HEADER_OFFSET][ACTIVE_INDEX] = 0; + lView[index + HEADER_OFFSET][ACTIVE_INDEX] = 0; if (!getCheckNoChangesMode()) { // We need to execute init hooks here so ngOnInit hooks are called in top level views // before they are called in embedded views (for backwards compatibility). - executeInitHooks(viewData, tView, getCreationMode()); + executeInitHooks(lView, tView, getCreationMode()); } } @@ -1907,14 +1910,14 @@ export function containerRefreshEnd(): void { setIsParent(false); } else { ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.View); - ngDevMode && assertHasParent(); + ngDevMode && assertHasParent(previousOrParentTNode); previousOrParentTNode = previousOrParentTNode.parent !; setPreviousOrParentTNode(previousOrParentTNode); } ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.Container); - const lContainer = getViewData()[previousOrParentTNode.index]; + const lContainer = getLView()[previousOrParentTNode.index]; const nextIndex = lContainer[ACTIVE_INDEX]; // remove extra views at the end of the container @@ -1927,10 +1930,10 @@ export function containerRefreshEnd(): void { * Goes over dynamic embedded views (ones created through ViewContainerRef APIs) and refreshes them * by executing an associated template function. */ -function refreshDynamicEmbeddedViews(lViewData: LViewData) { - for (let current = getLViewChild(lViewData); current !== null; current = current[NEXT]) { - // Note: current can be an LViewData or an LContainer instance, but here we are only interested - // in LContainer. We can tell it's an LContainer because its length is less than the LViewData +function refreshDynamicEmbeddedViews(lView: LView) { + for (let current = getLViewChild(lView); current !== null; current = current[NEXT]) { + // Note: current can be an LView or an LContainer instance, but here we are only interested + // in LContainer. We can tell it's an LContainer because its length is less than the LView // header. if (current.length < HEADER_OFFSET && current[ACTIVE_INDEX] === -1) { const container = current as LContainer; @@ -1959,7 +1962,7 @@ function refreshDynamicEmbeddedViews(lViewData: LViewData) { */ function scanForView( lContainer: LContainer, tContainerNode: TContainerNode, startIdx: number, - viewBlockId: number): LViewData|null { + viewBlockId: number): LView|null { const views = lContainer[VIEWS]; for (let i = startIdx; i < views.length; i++) { const viewAtPositionId = views[i][TVIEW].id; @@ -1985,13 +1988,13 @@ function scanForView( * @return boolean Whether or not this view is in creation mode */ export function embeddedViewStart(viewBlockId: number, consts: number, vars: number): RenderFlags { - const viewData = getViewData(); + const lView = getLView(); const previousOrParentTNode = getPreviousOrParentTNode(); // The previous node can be a view node if we are processing an inline for loop const containerTNode = previousOrParentTNode.type === TNodeType.View ? previousOrParentTNode.parent ! : previousOrParentTNode; - const lContainer = viewData[containerTNode.index] as LContainer; + const lContainer = lView[containerTNode.index] as LContainer; ngDevMode && assertNodeType(containerTNode, TNodeType.Container); let viewToRender = scanForView( @@ -2002,8 +2005,8 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num enterView(viewToRender, viewToRender[TVIEW].node); } else { // When we create a new LView, we always reset the state of the instructions. - viewToRender = createLViewData( - getViewData(), + viewToRender = createLView( + lView, getOrCreateEmbeddedTView(viewBlockId, consts, vars, containerTNode as TContainerNode), null, LViewFlags.CheckAlways); @@ -2017,7 +2020,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num if (lContainer) { if (getCreationMode()) { // it is a new view, insert it into collection of views for a given container - insertView(viewToRender, lContainer, viewData, lContainer[ACTIVE_INDEX] !, -1); + insertView(viewToRender, lContainer, lView, lContainer[ACTIVE_INDEX] !, -1); } lContainer[ACTIVE_INDEX] !++; } @@ -2039,7 +2042,7 @@ export function embeddedViewStart(viewBlockId: number, consts: number, vars: num */ function getOrCreateEmbeddedTView( viewIndex: number, consts: number, vars: number, parent: TContainerNode): TView { - const tView = getTView(); + const tView = getLView()[TVIEW]; ngDevMode && assertNodeType(parent, TNodeType.Container); const containerTViews = parent.tViews as TView[]; ngDevMode && assertDefined(containerTViews, 'TView expected'); @@ -2053,10 +2056,10 @@ function getOrCreateEmbeddedTView( /** Marks the end of an embedded view. */ export function embeddedViewEnd(): void { - const viewData = getViewData(); - const viewHost = viewData[HOST_NODE]; - refreshDescendantViews(viewData, null); - leaveView(viewData[PARENT] !); + const lView = getLView(); + const viewHost = lView[HOST_NODE]; + refreshDescendantViews(lView, null); + leaveView(lView[PARENT] !); setPreviousOrParentTNode(viewHost !); setIsParent(false); } @@ -2066,13 +2069,14 @@ export function embeddedViewEnd(): void { /** * Refreshes components by entering the component view and processing its bindings, queries, etc. * - * @param adjustedElementIndex Element index in LViewData[] (adjusted for HEADER_OFFSET) + * @param adjustedElementIndex Element index in LView[] (adjusted for HEADER_OFFSET) * @param rf The render flags that should be used to process this template */ export function componentRefresh(adjustedElementIndex: number, rf: RenderFlags | null): void { - ngDevMode && assertDataInRange(adjustedElementIndex); - const hostView = getComponentViewByIndex(adjustedElementIndex, getViewData()); - ngDevMode && assertNodeType(getTView().data[adjustedElementIndex] as TNode, TNodeType.Element); + const lView = getLView(); + ngDevMode && assertDataInRange(lView, adjustedElementIndex); + const hostView = getComponentViewByIndex(adjustedElementIndex, lView); + ngDevMode && assertNodeType(lView[TVIEW].data[adjustedElementIndex] as TNode, TNodeType.Element); // Only attached CheckAlways components or attached, dirty OnPush components should be checked if (viewAttached(hostView) && hostView[FLAGS] & (LViewFlags.CheckAlways | LViewFlags.Dirty)) { @@ -2082,7 +2086,7 @@ export function componentRefresh(adjustedElementIndex: number, rf: RenderFlag } /** - * Syncs an LViewData instance with its blueprint if they have gotten out of sync. + * Syncs an LView instance with its blueprint if they have gotten out of sync. * * Typically, blueprints and their view instances should always be in sync, so the loop here * will be skipped. However, consider this case of two components side-by-side: @@ -2095,19 +2099,19 @@ export function componentRefresh(adjustedElementIndex: number, rf: RenderFlag * * The following will happen: * 1. App template begins processing. - * 2. First is matched as a component and its LViewData is created. - * 3. Second is matched as a component and its LViewData is created. + * 2. First is matched as a component and its LView is created. + * 3. Second is matched as a component and its LView is created. * 4. App template completes processing, so it's time to check child templates. * 5. First template is checked. It has a directive, so its def is pushed to blueprint. * 6. Second template is checked. Its blueprint has been updated by the first - * template, but its LViewData was created before this update, so it is out of sync. + * template, but its LView was created before this update, so it is out of sync. * * Note that embedded views inside ngFor loops will never be out of sync because these views * are processed as soon as they are created. * * @param componentView The view to sync */ -function syncViewWithBlueprint(componentView: LViewData) { +function syncViewWithBlueprint(componentView: LView) { const componentTView = componentView[TVIEW]; for (let i = componentView.length; i < componentTView.blueprint.length; i++) { componentView[i] = componentTView.blueprint[i]; @@ -2115,7 +2119,7 @@ function syncViewWithBlueprint(componentView: LViewData) { } /** Returns a boolean for whether the view is attached */ -export function viewAttached(view: LViewData): boolean { +export function viewAttached(view: LView): boolean { return (view[FLAGS] & LViewFlags.Attached) === LViewFlags.Attached; } @@ -2141,7 +2145,7 @@ export function viewAttached(view: LViewData): boolean { * @param rawSelectors A collection of CSS selectors in the raw, un-parsed form */ export function projectionDef(selectors?: CssSelectorList[], textSelectors?: string[]): void { - const componentNode = findComponentView(getViewData())[HOST_NODE] as TElementNode; + const componentNode = findComponentView(getLView())[HOST_NODE] as TElementNode; if (!componentNode.projection) { const noOfNodeBuckets = selectors ? selectors.length + 1 : 1; @@ -2176,7 +2180,7 @@ export function projectionDef(selectors?: CssSelectorList[], textSelectors?: str * a new array each time the function is called. Instead the array will be * re-used by each invocation. This works because the function is not reentrant. */ -const projectionNodeStack: (LViewData | TNode)[] = []; +const projectionNodeStack: (LView | TNode)[] = []; /** * Inserts previously re-distributed projected nodes. This instruction must be preceded by a call @@ -2188,7 +2192,7 @@ const projectionNodeStack: (LViewData | TNode)[] = []; * - 1 based index of the selector from the {@link projectionDef} */ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: string[]): void { - const viewData = getViewData(); + const lView = getLView(); const tProjectionNode = createNodeAtIndex(nodeIndex, TNodeType.Projection, null, null, attrs || null); @@ -2199,7 +2203,7 @@ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: setIsParent(false); // re-distribution of projectable nodes is stored on a component's view level - const componentView = findComponentView(viewData); + const componentView = findComponentView(lView); const componentNode = componentView[HOST_NODE] as TElementNode; let nodeToProject = (componentNode.projection as(TNode | null)[])[selectorIndex]; let projectedView = componentView[PARENT] !; @@ -2225,13 +2229,13 @@ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: // This flag must be set now or we won't know that this node is projected // if the nodes are inserted into a container later. nodeToProject.flags |= TNodeFlags.isProjected; - appendProjectedNode(nodeToProject, tProjectionNode, viewData, projectedView); + appendProjectedNode(nodeToProject, tProjectionNode, lView, projectedView); } // If we are finished with a list of re-projected nodes, we need to get // back to the root projection node that was re-projected. if (nodeToProject.next === null && projectedView !== componentView[PARENT] !) { - projectedView = projectionNodeStack[projectionNodeIndex--] as LViewData; + projectedView = projectionNodeStack[projectionNodeIndex--] as LView; nodeToProject = projectionNodeStack[projectionNodeIndex--] as TNode; } nodeToProject = nodeToProject.next; @@ -2239,26 +2243,26 @@ export function projection(nodeIndex: number, selectorIndex: number = 0, attrs?: } /** - * Adds LViewData or LContainer to the end of the current view tree. + * Adds LView or LContainer to the end of the current view tree. * * This structure will be used to traverse through nested views to remove listeners * and call onDestroy callbacks. * - * @param currentView The view where LViewData or LContainer should be added - * @param adjustedHostIndex Index of the view's host node in LViewData[], adjusted for header - * @param state The LViewData or LContainer to add to the view tree + * @param lView The view where LView or LContainer should be added + * @param adjustedHostIndex Index of the view's host node in LView[], adjusted for header + * @param state The LView or LContainer to add to the view tree * @returns The state passed in */ -export function addToViewTree( - currentView: LViewData, adjustedHostIndex: number, state: T): T { - const tView = getTView(); +export function addToViewTree( + lView: LView, adjustedHostIndex: number, state: T): T { + const tView = lView[TVIEW]; const firstTemplatePass = getFirstTemplatePass(); - if (currentView[TAIL]) { - currentView[TAIL] ![NEXT] = state; + if (lView[TAIL]) { + lView[TAIL] ![NEXT] = state; } else if (firstTemplatePass) { tView.childIndex = adjustedHostIndex; } - currentView[TAIL] = state; + lView[TAIL] = state; return state; } @@ -2266,11 +2270,11 @@ export function addToViewTree( //// Change detection /////////////////////////////// -/** If node is an OnPush component, marks its LViewData dirty. */ -function markDirtyIfOnPush(viewData: LViewData, viewIndex: number): void { - const view = getComponentViewByIndex(viewIndex, viewData); - if (!(view[FLAGS] & LViewFlags.CheckAlways)) { - view[FLAGS] |= LViewFlags.Dirty; +/** If node is an OnPush component, marks its LView dirty. */ +function markDirtyIfOnPush(lView: LView, viewIndex: number): void { + const childComponentLView = getComponentViewByIndex(viewIndex, lView); + if (!(childComponentLView[FLAGS] & LViewFlags.CheckAlways)) { + childComponentLView[FLAGS] |= LViewFlags.Dirty; } } @@ -2286,17 +2290,15 @@ function wrapListenerWithPreventDefault(listenerFn: (e?: any) => any): EventList } /** Marks current view and all ancestors dirty */ -export function markViewDirty(view: LViewData): void { - let currentView: LViewData = view; - - while (currentView && !(currentView[FLAGS] & LViewFlags.IsRoot)) { - currentView[FLAGS] |= LViewFlags.Dirty; - currentView = currentView[PARENT] !; +export function markViewDirty(lView: LView): void { + while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { + lView[FLAGS] |= LViewFlags.Dirty; + lView = lView[PARENT] !; } - currentView[FLAGS] |= LViewFlags.Dirty; - ngDevMode && assertDefined(currentView[CONTEXT], 'rootContext should be defined'); + lView[FLAGS] |= LViewFlags.Dirty; + ngDevMode && assertDefined(lView[CONTEXT], 'rootContext should be defined'); - const rootContext = currentView[CONTEXT] as RootContext; + const rootContext = lView[CONTEXT] as RootContext; scheduleTick(rootContext, RootContextFlags.DetectChanges); } @@ -2359,8 +2361,7 @@ export function tick(component: T): void { function tickRootContext(rootContext: RootContext) { for (let i = 0; i < rootContext.components.length; i++) { const rootComponent = rootContext.components[i]; - renderComponentOrTemplate( - readPatchedLViewData(rootComponent) !, rootComponent, RenderFlags.Update); + renderComponentOrTemplate(readPatchedLView(rootComponent) !, rootComponent, RenderFlags.Update); } } @@ -2384,10 +2385,10 @@ export function detectChanges(component: T): void { /** * Synchronously perform change detection on a root view and its components. * - * @param lViewData The view which the change detection should be performed on. + * @param lView The view which the change detection should be performed on. */ -export function detectChangesInRootView(lViewData: LViewData): void { - tickRootContext(lViewData[CONTEXT] as RootContext); +export function detectChangesInRootView(lView: LView): void { + tickRootContext(lView[CONTEXT] as RootContext); } @@ -2413,19 +2414,19 @@ export function checkNoChanges(component: T): void { * This is used in development mode to verify that running change detection doesn't * introduce other changes. * - * @param lViewData The view which the change detection should be checked on. + * @param lView The view which the change detection should be checked on. */ -export function checkNoChangesInRootView(lViewData: LViewData): void { +export function checkNoChangesInRootView(lView: LView): void { setCheckNoChangesMode(true); try { - detectChangesInRootView(lViewData); + detectChangesInRootView(lView); } finally { setCheckNoChangesMode(false); } } /** Checks the view of the component provided. Does not gate on dirty checks or execute doCheck. */ -function detectChangesInternal(hostView: LViewData, component: T, rf: RenderFlags | null) { +function detectChangesInternal(hostView: LView, component: T, rf: RenderFlags | null) { const hostTView = hostView[TVIEW]; const oldView = enterView(hostView, hostView[HOST_NODE]); const templateFn = hostTView.template !; @@ -2490,7 +2491,8 @@ export function markDirty(component: T) { * @param value Value to diff */ export function bind(value: T): T|NO_CHANGE { - return bindingUpdated(getViewData()[BINDING_INDEX]++, value) ? value : NO_CHANGE; + const lView = getLView(); + return bindingUpdated(lView, lView[BINDING_INDEX]++, value) ? value : NO_CHANGE; } /** @@ -2509,11 +2511,14 @@ export function interpolationV(values: any[]): string|NO_CHANGE { ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values'); ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values'); let different = false; + const lView = getLView(); + let bindingIndex = lView[BINDING_INDEX]; for (let i = 1; i < values.length; i += 2) { // Check if bindings (odd indexes) have changed - bindingUpdated(getViewData()[BINDING_INDEX]++, values[i]) && (different = true); + bindingUpdated(lView, bindingIndex++, values[i]) && (different = true); } + lView[BINDING_INDEX] = bindingIndex; if (!different) { return NO_CHANGE; @@ -2536,16 +2541,18 @@ export function interpolationV(values: any[]): string|NO_CHANGE { * @param suffix static value used for concatenation only. */ export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE { - const different = bindingUpdated(getViewData()[BINDING_INDEX]++, v0); + const lView = getLView(); + const different = bindingUpdated(lView, lView[BINDING_INDEX], v0); + lView[BINDING_INDEX] += 1; return different ? prefix + stringify(v0) + suffix : NO_CHANGE; } /** Creates an interpolation binding with 2 expressions. */ export function interpolation2( prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE { - const viewData = getViewData(); - const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1); - viewData[BINDING_INDEX] += 2; + const lView = getLView(); + const different = bindingUpdated2(lView, lView[BINDING_INDEX], v0, v1); + lView[BINDING_INDEX] += 2; return different ? prefix + stringify(v0) + i0 + stringify(v1) + suffix : NO_CHANGE; } @@ -2554,9 +2561,9 @@ export function interpolation2( export function interpolation3( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string| NO_CHANGE { - const viewData = getViewData(); - const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2); - viewData[BINDING_INDEX] += 3; + const lView = getLView(); + const different = bindingUpdated3(lView, lView[BINDING_INDEX], v0, v1, v2); + lView[BINDING_INDEX] += 3; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + suffix : NO_CHANGE; @@ -2566,9 +2573,9 @@ export function interpolation3( export function interpolation4( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, suffix: string): string|NO_CHANGE { - const viewData = getViewData(); - const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); - viewData[BINDING_INDEX] += 4; + const lView = getLView(); + const different = bindingUpdated4(lView, lView[BINDING_INDEX], v0, v1, v2, v3); + lView[BINDING_INDEX] += 4; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + @@ -2580,10 +2587,11 @@ export function interpolation4( export function interpolation5( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string): string|NO_CHANGE { - const viewData = getViewData(); - let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); - different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different; - viewData[BINDING_INDEX] += 5; + const lView = getLView(); + const bindingIndex = lView[BINDING_INDEX]; + let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); + different = bindingUpdated(lView, bindingIndex + 4, v4) || different; + lView[BINDING_INDEX] += 5; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + @@ -2595,10 +2603,11 @@ export function interpolation5( export function interpolation6( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): string|NO_CHANGE { - const viewData = getViewData(); - let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); - different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different; - viewData[BINDING_INDEX] += 6; + const lView = getLView(); + const bindingIndex = lView[BINDING_INDEX]; + let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); + different = bindingUpdated2(lView, bindingIndex + 4, v4, v5) || different; + lView[BINDING_INDEX] += 6; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + @@ -2611,10 +2620,11 @@ export function interpolation7( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): string| NO_CHANGE { - const viewData = getViewData(); - let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); - different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different; - viewData[BINDING_INDEX] += 7; + const lView = getLView(); + const bindingIndex = lView[BINDING_INDEX]; + let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); + different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different; + lView[BINDING_INDEX] += 7; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + @@ -2627,10 +2637,11 @@ export function interpolation8( prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, suffix: string): string|NO_CHANGE { - const viewData = getViewData(); - let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3); - different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different; - viewData[BINDING_INDEX] += 8; + const lView = getLView(); + const bindingIndex = lView[BINDING_INDEX]; + let different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); + different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different; + lView[BINDING_INDEX] += 8; return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 + @@ -2640,14 +2651,15 @@ export function interpolation8( /** Store a value in the `data` at a given `index`. */ export function store(index: number, value: T): void { - const tView = getTView(); + const lView = getLView(); + const tView = lView[TVIEW]; // We don't store any static data for local variables, so the first time // we see the template, we should store as null to avoid a sparse array const adjustedIndex = index + HEADER_OFFSET; if (adjustedIndex >= tView.data.length) { tView.data[adjustedIndex] = null; } - getViewData()[adjustedIndex] = value; + lView[adjustedIndex] = value; } /** @@ -2659,76 +2671,25 @@ export function store(index: number, value: T): void { * @param index The index of the local ref in contextViewData. */ export function reference(index: number) { - const contextViewData = getContextViewData(); - return loadInternal(index, contextViewData); + const contextLView = getContextLView(); + return loadInternal(contextLView, index); } export function loadQueryList(queryListIdx: number): QueryList { - const viewData = getViewData(); - ngDevMode && assertDefined( - viewData[CONTENT_QUERIES], - 'Content QueryList array should be defined if reading a query.'); - ngDevMode && assertDataInRange(queryListIdx, viewData[CONTENT_QUERIES] !); + const lView = getLView(); + ngDevMode && + assertDefined( + lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.'); + ngDevMode && assertDataInRange(lView[CONTENT_QUERIES] !, queryListIdx); - return viewData[CONTENT_QUERIES] ![queryListIdx]; + return lView[CONTENT_QUERIES] ![queryListIdx]; } /** Retrieves a value from current `viewData`. */ export function load(index: number): T { - return loadInternal(index, getViewData()); + return loadInternal(getLView(), index); } -/** Gets the current binding value. */ -export function getBinding(bindingIndex: number): any { - const viewData = getViewData(); - ngDevMode && assertDataInRange(viewData[bindingIndex]); - ngDevMode && - assertNotEqual(viewData[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.'); - return viewData[bindingIndex]; -} - -/** Updates binding if changed, then returns whether it was updated. */ -export function bindingUpdated(bindingIndex: number, value: any): boolean { - const viewData = getViewData(); - const checkNoChangesMode = getCheckNoChangesMode(); - ngDevMode && assertNotEqual(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.'); - ngDevMode && assertLessThan( - bindingIndex, viewData.length, `Slot should have been initialized to NO_CHANGE`); - - if (viewData[bindingIndex] === NO_CHANGE) { - viewData[bindingIndex] = value; - } else if (isDifferent(viewData[bindingIndex], value, checkNoChangesMode)) { - throwErrorIfNoChangesMode(getCreationMode(), checkNoChangesMode, viewData[bindingIndex], value); - viewData[bindingIndex] = value; - } else { - return false; - } - return true; -} - -/** Updates binding and returns the value. */ -export function updateBinding(bindingIndex: number, value: any): any { - return getViewData()[bindingIndex] = value; -} - -/** Updates 2 bindings if changed, then returns whether either was updated. */ -export function bindingUpdated2(bindingIndex: number, exp1: any, exp2: any): boolean { - const different = bindingUpdated(bindingIndex, exp1); - return bindingUpdated(bindingIndex + 1, exp2) || different; -} - -/** Updates 3 bindings if changed, then returns whether any was updated. */ -export function bindingUpdated3(bindingIndex: number, exp1: any, exp2: any, exp3: any): boolean { - const different = bindingUpdated2(bindingIndex, exp1, exp2); - return bindingUpdated(bindingIndex + 2, exp3) || different; -} - -/** Updates 4 bindings if changed, then returns whether any was updated. */ -export function bindingUpdated4( - bindingIndex: number, exp1: any, exp2: any, exp3: any, exp4: any): boolean { - const different = bindingUpdated2(bindingIndex, exp1, exp2); - return bindingUpdated2(bindingIndex + 2, exp3, exp4) || different; -} /////////////////////////////// @@ -2763,7 +2724,7 @@ export function directiveInject( token = resolveForwardRef(token); return getOrCreateInjectable( getPreviousOrParentTNode() as TElementNode | TContainerNode | TElementContainerNode, - getViewData(), token, flags); + getLView(), token, flags); } /** @@ -2779,8 +2740,8 @@ export function injectAttribute(attrNameToInject: string): string|null { */ export function registerContentQuery( queryList: QueryList, currentDirectiveIndex: number): void { - const viewData = getViewData(); - const tView = getTView(); + const viewData = getLView(); + const tView = viewData[TVIEW]; const savedContentQueriesLength = (viewData[CONTENT_QUERIES] || (viewData[CONTENT_QUERIES] = [])).push(queryList); if (getFirstTemplatePass()) { @@ -2811,3 +2772,24 @@ function initializeTNodeInputs(tNode: TNode | null) { export function delegateToClassInput(tNode: TNode) { return tNode.flags & TNodeFlags.hasClassInput; } + + +/** + * Returns the current OpaqueViewState instance. + * + * Used in conjunction with the restoreView() instruction to save a snapshot + * of the current view and restore it when listeners are invoked. This allows + * walking the declaration view tree in listeners to get vars from parent views. + */ +export function getCurrentView(): OpaqueViewState { + return getLView() as any as OpaqueViewState; +} + +function getCleanup(view: LView): any[] { + // top level variables should not be exported for performance reasons (PERF_NOTES.md) + return view[CLEANUP] || (view[CLEANUP] = []); +} + +function getTViewCleanup(view: LView): any[] { + return view[TVIEW].cleanup || (view[TVIEW].cleanup = []); +} diff --git a/packages/core/src/render3/interfaces/container.ts b/packages/core/src/render3/interfaces/container.ts index e2682c51d3..5a0e0e50be 100644 --- a/packages/core/src/render3/interfaces/container.ts +++ b/packages/core/src/render3/interfaces/container.ts @@ -9,7 +9,7 @@ import {LQueries} from './query'; import {RComment, RElement} from './renderer'; import {StylingContext} from './styling'; -import {HOST, LViewData, NEXT, PARENT, QUERIES} from './view'; +import {HOST, LView, NEXT, PARENT, QUERIES} from './view'; /** @@ -20,14 +20,14 @@ import {HOST, LViewData, NEXT, PARENT, QUERIES} from './view'; export const ACTIVE_INDEX = 0; export const VIEWS = 1; // PARENT, NEXT, QUERIES, and HOST are indices 2, 3, 4, and 5. -// As we already have these constants in LViewData, we don't need to re-create them. +// As we already have these constants in LView, we don't need to re-create them. export const NATIVE = 6; export const RENDER_PARENT = 7; /** * 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 LView. This helps * when traversing the view tree (which is a mix of containers and component * views), so we can jump to viewOrContainer[NEXT] in the same way regardless * of type. @@ -49,19 +49,19 @@ export interface LContainer extends Array { * (and don't need to be re-added) and so we can remove views from the DOM when they * are no longer required. */ - [VIEWS]: LViewData[]; + [VIEWS]: LView[]; /** * Access to the parent view is necessary so we can propagate back * up from inside a container to parent[NEXT]. */ - [PARENT]: LViewData|null; + [PARENT]: LView|null; /** * This allows us to jump from a container to a sibling container or component * view with the same parent, so we can remove listeners efficiently. */ - [NEXT]: LViewData|LContainer|null; + [NEXT]: LView|LContainer|null; /** * Queries active for this container - all the views inserted to / removed from @@ -72,13 +72,13 @@ export interface LContainer extends Array { /** * The host element of this LContainer. * - * The host could be an LViewData if this container is on a component node. - * In that case, the component LViewData is its HOST. + * The host could be an LView if this container is on a component node. + * In that case, the component LView 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; + [HOST]: RElement|RComment|StylingContext|LView; /** The comment element that serves as an anchor for this LContainer. */ [NATIVE]: RComment; diff --git a/packages/core/src/render3/interfaces/context.ts b/packages/core/src/render3/interfaces/context.ts index 7f896ddafe..e1bab45c72 100644 --- a/packages/core/src/render3/interfaces/context.ts +++ b/packages/core/src/render3/interfaces/context.ts @@ -8,7 +8,7 @@ import {RElement} from './renderer'; -import {LViewData} from './view'; +import {LView} from './view'; /** * This property will be monkey-patched on elements, components and directives @@ -17,7 +17,7 @@ export const MONKEY_PATCH_KEY_NAME = '__ngContext__'; /** * The internal view context which is specific to a given DOM element, directive or - * component instance. Each value in here (besides the LViewData and element node details) + * component instance. Each value in here (besides the LView and element node details) * can be present, null or undefined. If undefined then it implies the value has not been * looked up yet, otherwise, if null, then a lookup was executed and nothing was found. * @@ -29,7 +29,7 @@ export interface LContext { /** * The component's parent view data. */ - lViewData: LViewData; + lView: LView; /** * The index instance of the node. diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index 2b89774ce6..0bb01335cd 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -139,7 +139,7 @@ export interface DirectiveDef extends BaseDef { /** * The number of host bindings (including pure fn bindings) in this directive/component. * - * Used to calculate the length of the LViewData array for the *parent* component + * Used to calculate the length of the LView array for the *parent* component * of this directive/component. */ readonly hostVars: number; @@ -205,7 +205,7 @@ export interface ComponentDef extends DirectiveDef { /** * The number of nodes, local refs, and pipes in this component template. * - * Used to calculate the length of the component's LViewData array, so we + * Used to calculate the length of the component's LView array, so we * can pre-fill the array and set the binding start index. */ // TODO(kara): remove queries from this count @@ -214,7 +214,7 @@ export interface ComponentDef extends DirectiveDef { /** * The number of bindings in this component template (including pure fn bindings). * - * Used to calculate the length of the component's LViewData array, so we + * Used to calculate the length of the component's LView array, so we * can pre-fill the array and set the host binding start index. */ readonly vars: number; diff --git a/packages/core/src/render3/interfaces/i18n.ts b/packages/core/src/render3/interfaces/i18n.ts index f50b9a4c4e..02da87ebc9 100644 --- a/packages/core/src/render3/interfaces/i18n.ts +++ b/packages/core/src/render3/interfaces/i18n.ts @@ -74,60 +74,60 @@ export interface COMMENT_MARKER { marker: 'comment'; } * // For adding text nodes * // --------------------- * // Equivalent to: - * // const node = lViewData[index++] = document.createTextNode('abc'); - * // lViewData[1].insertBefore(node, lViewData[2]); + * // const node = lView[index++] = document.createTextNode('abc'); + * // lView[1].insertBefore(node, lView[2]); * 'abc', 1 << SHIFT_PARENT | 2 << SHIFT_REF | InsertBefore, * * // Equivalent to: - * // const node = lViewData[index++] = document.createTextNode('xyz'); - * // lViewData[1].appendChild(node); + * // const node = lView[index++] = document.createTextNode('xyz'); + * // lView[1].appendChild(node); * 'xyz', 1 << SHIFT_PARENT | AppendChild, * * // For adding element nodes * // --------------------- * // Equivalent to: - * // const node = lViewData[index++] = document.createElement('div'); - * // lViewData[1].insertBefore(node, lViewData[2]); + * // const node = lView[index++] = document.createElement('div'); + * // lView[1].insertBefore(node, lView[2]); * ELEMENT_MARKER, 'div', 1 << SHIFT_PARENT | 2 << SHIFT_REF | InsertBefore, * * // Equivalent to: - * // const node = lViewData[index++] = document.createElement('div'); - * // lViewData[1].appendChild(node); + * // const node = lView[index++] = document.createElement('div'); + * // lView[1].appendChild(node); * ELEMENT_MARKER, 'div', 1 << SHIFT_PARENT | AppendChild, * * // For adding comment nodes * // --------------------- * // Equivalent to: - * // const node = lViewData[index++] = document.createComment(''); - * // lViewData[1].insertBefore(node, lViewData[2]); + * // const node = lView[index++] = document.createComment(''); + * // lView[1].insertBefore(node, lView[2]); * COMMENT_MARKER, '', 1 << SHIFT_PARENT | 2 << SHIFT_REF | InsertBefore, * * // Equivalent to: - * // const node = lViewData[index++] = document.createComment(''); - * // lViewData[1].appendChild(node); + * // const node = lView[index++] = document.createComment(''); + * // lView[1].appendChild(node); * COMMENT_MARKER, '', 1 << SHIFT_PARENT | AppendChild, * * // For moving existing nodes to a different location * // -------------------------------------------------- * // Equivalent to: - * // const node = lViewData[1]; - * // lViewData[2].insertBefore(node, lViewData[3]); + * // const node = lView[1]; + * // lView[2].insertBefore(node, lView[3]); * 1 << SHIFT_REF | Select, 2 << SHIFT_PARENT | 3 << SHIFT_REF | InsertBefore, * * // Equivalent to: - * // const node = lViewData[1]; - * // lViewData[2].appendChild(node); + * // const node = lView[1]; + * // lView[2].appendChild(node); * 1 << SHIFT_REF | Select, 2 << SHIFT_PARENT | AppendChild, * * // For removing existing nodes * // -------------------------------------------------- - * // const node = lViewData[1]; - * // removeChild(tView.data(1), node, lViewData); + * // const node = lView[1]; + * // removeChild(tView.data(1), node, lView); * 1 << SHIFT_REF | Remove, * * // For writing attributes * // -------------------------------------------------- - * // const node = lViewData[1]; + * // const node = lView[1]; * // node.setAttribute('attr', 'value'); * 1 << SHIFT_REF | Select, 'attr', 'value' * // NOTE: Select followed by two string (vs select followed by OpCode) @@ -196,7 +196,7 @@ export const enum I18nUpdateOpCode { * // has changed then execute update OpCodes. * // has NOT changed then skip `7` values and start processing next OpCodes. * 0b11, 7, - * // Concatenate `newValue = 'pre'+lViewData[bindIndex-4]+'in'+lViewData[bindIndex-3]+'post';`. + * // Concatenate `newValue = 'pre'+lView[bindIndex-4]+'in'+lView[bindIndex-3]+'post';`. * 'pre', -4, 'in', -3, 'post', * // Update attribute: `elementAttribute(1, 'title', sanitizerFn(newValue));` * 1 << SHIFT_REF | Attr, 'title', sanitizerFn, @@ -206,9 +206,9 @@ export const enum I18nUpdateOpCode { * // has changed then execute update OpCodes. * // has NOT changed then skip `4` values and start processing next OpCodes. * 0b100, 4, - * // Concatenate `newValue = 'Hello ' + lViewData[bindIndex -2] + '!';`. + * // Concatenate `newValue = 'Hello ' + lView[bindIndex -2] + '!';`. * 'Hello ', -2, '!', - * // Update text: `lViewData[1].textContent = newValue;` + * // Update text: `lView[1].textContent = newValue;` * 1 << SHIFT_REF | Text, * * // The following OpCodes represent: `
{exp4, plural, ... }">` @@ -216,14 +216,14 @@ export const enum I18nUpdateOpCode { * // has changed then execute update OpCodes. * // has NOT changed then skip `4` values and start processing next OpCodes. * 0b1000, 4, - * // Concatenate `newValue = lViewData[bindIndex -1];`. + * // Concatenate `newValue = lView[bindIndex -1];`. * -1, - * // Switch ICU: `icuSwitchCase(lViewData[1], 0, newValue);` + * // Switch ICU: `icuSwitchCase(lView[1], 0, newValue);` * 0 << SHIFT_ICU | 1 << SHIFT_REF | IcuSwitch, * * // Note `changeMask & -1` is always true, so the IcuUpdate will always execute. * -1, 1, - * // Update ICU: `icuUpdateCase(lViewData[1], 0);` + * // Update ICU: `icuUpdateCase(lView[1], 0);` * 0 << SHIFT_ICU | 1 << SHIFT_REF | IcuUpdate, * * ]; diff --git a/packages/core/src/render3/interfaces/injector.ts b/packages/core/src/render3/interfaces/injector.ts index b49f94cf69..e790c145a9 100644 --- a/packages/core/src/render3/interfaces/injector.ts +++ b/packages/core/src/render3/interfaces/injector.ts @@ -10,7 +10,7 @@ import {InjectionToken} from '../../di/injection_token'; import {InjectFlags} from '../../di/injector_compatibility'; import {Type} from '../../type'; import {TElementNode} from './node'; -import {LViewData, TData} from './view'; +import {LView, TData} from './view'; export const TNODE = 8; export const PARENT_INJECTOR = 8; @@ -19,7 +19,7 @@ export const INJECTOR_SIZE = 9; /** * Represents a relative location of parent injector. * - * The interfaces encodes number of parents `LViewData`s to traverse and index in the `LViewData` + * The interfaces encodes number of parents `LView`s to traverse and index in the `LView` * pointing to the parent injector. */ export interface RelativeInjectorLocation { __brand__: 'RelativeInjectorLocationFlags'; } @@ -34,10 +34,10 @@ export const enum RelativeInjectorLocationFlags { export const NO_PARENT_INJECTOR: RelativeInjectorLocation = -1 as any; /** - * Each injector is saved in 9 contiguous slots in `LViewData` and 9 contiguous slots in + * Each injector is saved in 9 contiguous slots in `LView` and 9 contiguous slots in * `TView.data`. This allows us to store information about the current node's tokens (which * can be shared in `TView`) as well as the tokens of its ancestor nodes (which cannot be - * shared, so they live in `LViewData`). + * shared, so they live in `LView`). * * Each of these slots (aside from the last slot) contains a bloom filter. This bloom filter * determines whether a directive is available on the associated node or not. This prevents us @@ -45,7 +45,7 @@ export const NO_PARENT_INJECTOR: RelativeInjectorLocation = -1 as any; * * See: https://en.wikipedia.org/wiki/Bloom_filter for more about bloom filters. * - * Because all injectors have been flattened into `LViewData` and `TViewData`, they cannot typed + * Because all injectors have been flattened into `LView` and `TViewData`, they cannot typed * using interfaces as they were previously. The start index of each `LInjector` and `TInjector` * will differ based on where it is flattened into the main array, so it's not possible to know * the indices ahead of time and save their types here. The interfaces are still included here @@ -226,7 +226,7 @@ export class NodeInjectorFactory { * array where existing instances of injectables are stored. This is used in case * of multi shadow is needed. See `multi` field documentation. */ - lData: LViewData, + lView: LView, /** * The TNode of the same element injector. */ diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 5dcb059148..007564cdda 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -7,7 +7,7 @@ */ import {StylingContext} from './styling'; -import {LViewData, TView} from './view'; +import {LView, TView} from './view'; /** @@ -103,7 +103,7 @@ export interface TNode { type: TNodeType; /** - * Index of the TNode in TView.data and corresponding native element in LViewData. + * Index of the TNode in TView.data and corresponding native element in LView. * * This is necessary to get from any TNode to its corresponding native element when * traversing the node tree. @@ -113,7 +113,7 @@ export interface TNode { index: number; /** - * The index of the closest injector in this node's LViewData. + * The index of the closest injector in this node's LView. * * If the index === -1, there is no injector on this node or any ancestor node in this view. * @@ -361,7 +361,7 @@ export interface TContainerNode extends TNode { /** Static data for an */ export interface TElementContainerNode extends TNode { - /** Index in the LViewData[] array. */ + /** Index in the LView[] array. */ index: number; child: TElementNode|TTextNode|TContainerNode|TElementContainerNode|TProjectionNode|null; parent: TElementNode|TElementContainerNode|null; @@ -371,7 +371,7 @@ export interface TElementContainerNode extends TNode { /** Static data for an ICU expression */ export interface TIcuContainerNode extends TNode { - /** Index in the LViewData[] array. */ + /** Index in the LView[] array. */ index: number; child: TElementNode|TTextNode|null; parent: TElementNode|TElementContainerNode|null; @@ -481,4 +481,4 @@ export type TNodeWithLocalRefs = TContainerNode | TElementNode | TElementContain * - `
` - `nativeDivEl` should point to the native `
` element; * - `` - `tplRef` should point to the `TemplateRef` instance; */ -export type LocalRefExtractor = (tNode: TNodeWithLocalRefs, currentView: LViewData) => any; +export type LocalRefExtractor = (tNode: TNodeWithLocalRefs, currentView: LView) => any; diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 7a8f11a64d..73cda62238 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -21,7 +21,7 @@ import {RElement, Renderer3, RendererFactory3} from './renderer'; import {StylingContext} from './styling'; -// Below are constants for LViewData indices to help us look up LViewData members +// Below are constants for LView indices to help us look up LView members // without having to remember the specific indices. // Uglify will inline these when minifying so there shouldn't be a cost. export const TVIEW = 0; @@ -42,11 +42,11 @@ export const TAIL = 14; export const CONTAINER_INDEX = 15; export const CONTENT_QUERIES = 16; export const DECLARATION_VIEW = 17; -/** Size of LViewData's header. Necessary to adjust for it when setting slots. */ +/** Size of LView's header. Necessary to adjust for it when setting slots. */ export const HEADER_OFFSET = 18; -// This interface replaces the real LViewData interface if it is an arg or a +// This interface replaces the real LView interface if it is an arg or a // return value of a public instruction. This ensures we don't need to expose // the actual interface, which should be kept private. export interface OpaqueViewState { @@ -55,16 +55,16 @@ export interface OpaqueViewState { /** - * `LViewData` stores all of the information needed to process the instructions as + * `LView` stores all of the information needed to process the instructions as * they are invoked from the template. Each embedded view and component view has its - * own `LViewData`. When processing a particular view, we set the `viewData` to that - * `LViewData`. When that view is done processing, the `viewData` is set back to - * whatever the original `viewData` was before (the parent `LViewData`). + * own `LView`. When processing a particular view, we set the `viewData` to that + * `LView`. When that view is done processing, the `viewData` is set back to + * whatever the original `viewData` was before (the parent `LView`). * * Keeping separate state for each view facilities view insertion / deletion, so we * don't have to edit the data array based on which views are present. */ -export interface LViewData extends Array { +export interface LView extends Array { /** * The static data for this view. We need a reference to this so we can easily walk up the * node tree in DI and get the TView.data array associated with a node (where the @@ -77,30 +77,30 @@ export interface LViewData extends Array { /** * The parent view is needed when we exit the view and must restore the previous - * `LViewData`. Without this, the render method would have to keep a stack of + * `LView`. Without this, the render method would have to keep a stack of * views as it is recursively rendering templates. * * This is the "insertion" view for embedded views. This allows us to properly * destroy embedded views. */ - [PARENT]: LViewData|null; + [PARENT]: LView|null; /** * - * The next sibling LViewData or LContainer. + * The next sibling LView or LContainer. * * Allows us to propagate between sibling view states that aren't in the same * container. Embedded views already have a node.next, but it is only set for * views in the same container. We need a way to link component views and views * across containers as well. */ - [NEXT]: LViewData|LContainer|null; + [NEXT]: LView|LContainer|null; /** Queries active for this view - nodes from a view are reported to those queries. */ [QUERIES]: LQueries|null; /** - * The host node for this LViewData instance, if this is a component view. + * The host node for this LView instance, if this is a component view. * * If this is an embedded view, HOST will be null. */ @@ -135,7 +135,7 @@ export interface LViewData extends Array { * These change per LView instance, so they cannot be stored on TView. Instead, * TView.cleanup saves an index to the necessary context in this array. */ - // TODO: flatten into LViewData[] + // TODO: flatten into LView[] [CLEANUP]: any[]|null; /** @@ -160,12 +160,12 @@ export interface LViewData extends Array { [SANITIZER]: Sanitizer|null; /** - * The last LViewData or LContainer beneath this LViewData in the hierarchy. + * The last LView or LContainer beneath this LView in the hierarchy. * * The tail allows us to quickly add a new state to the end of the view list * without having to propagate starting from the first child. */ - [TAIL]: LViewData|LContainer|null; + [TAIL]: LView|LContainer|null; /** * The index of the parent container's host node. Applicable only to embedded views that @@ -191,7 +191,7 @@ export interface LViewData extends Array { * * The template for a dynamically created view may be declared in a different view than * it is inserted. We already track the "insertion view" (view where the template was - * inserted) in LViewData[PARENT], but we also need access to the "declaration view" + * inserted) in LView[PARENT], but we also need access to the "declaration view" * (view where the template was declared). Otherwise, we wouldn't be able to call the * view's template function with the proper contexts. Context should be inherited from * the declaration view tree, not the insertion view tree. @@ -208,10 +208,10 @@ export interface LViewData extends Array { * template function during change detection, we need the declaration view to get inherited * context. */ - [DECLARATION_VIEW]: LViewData|null; + [DECLARATION_VIEW]: LView|null; } -/** Flags associated with an LView (saved in LViewData[FLAGS]) */ +/** Flags associated with an LView (saved in LView[FLAGS]) */ export const enum LViewFlags { /** * Whether or not the view is in creationMode. @@ -265,10 +265,10 @@ export interface TView { readonly id: number; /** - * This is a blueprint used to generate LViewData instances for this TView. Copying this - * blueprint is faster than creating a new LViewData from scratch. + * This is a blueprint used to generate LView instances for this TView. Copying this + * blueprint is faster than creating a new LView from scratch. */ - blueprint: LViewData; + blueprint: LView; /** * The template function used to refresh the view of dynamically created views @@ -313,9 +313,9 @@ export interface TView { bindingStartIndex: number; /** - * The index where the "expando" section of `LViewData` begins. The expando + * The index where the "expando" section of `LView` begins. The expando * section contains injectors, directive instances, and host binding values. - * Unlike the "consts" and "vars" sections of `LViewData`, the length of this + * Unlike the "consts" and "vars" sections of `LView`, the length of this * section cannot be calculated at compile-time because directives are matched * at runtime to preserve locality. * diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 8637c107fc..681b9678cc 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -13,14 +13,14 @@ import {LContainer, NATIVE, RENDER_PARENT, VIEWS, unusedValueExportToPlacateAjd import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; -import {CLEANUP, CONTAINER_INDEX, 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, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {assertNodeType} from './node_assert'; import {getNativeByTNode, isLContainer, isRootView, readElementValue, stringify} from './util'; const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5; /** Retrieves the parent element of a given node. */ -export function getParentNative(tNode: TNode, currentView: LViewData): RElement|RComment|null { +export function getParentNative(tNode: TNode, currentView: LView): RElement|RComment|null { if (tNode.parent == null) { return getHostNative(currentView); } else { @@ -44,14 +44,14 @@ function getFirstParentNative(tNode: TNode): TNode { * Gets the host element given a view. Will return null if the current view is an embedded view, * which does not have a host element. */ -export function getHostNative(currentView: LViewData): RElement|null { +export function getHostNative(currentView: LView): RElement|null { const hostTNode = currentView[HOST_NODE] as TElementNode; return hostTNode && hostTNode.type !== TNodeType.View ? (getNativeByTNode(hostTNode, currentView[PARENT] !) as RElement) : null; } -export function getLContainer(tNode: TViewNode, embeddedView: LViewData): LContainer|null { +export function getLContainer(tNode: TViewNode, embeddedView: LView): LContainer|null { if (tNode.index === -1) { // This is a dynamically created view inside a dynamic container. // If the host index is -1, the view has not yet been inserted, so it has no parent. @@ -68,7 +68,7 @@ export function getLContainer(tNode: TViewNode, embeddedView: LViewData): LConta * Retrieves render parent for a given view. * Might be null if a view is not yet attached to any container. */ -export function getContainerRenderParent(tViewNode: TViewNode, view: LViewData): RElement|null { +export function getContainerRenderParent(tViewNode: TViewNode, view: LView): RElement|null { const container = getLContainer(tViewNode, view); return container ? container[RENDER_PARENT] : null; } @@ -92,7 +92,7 @@ const enum WalkTNodeTreeAction { * a new array each time the function is called. Instead the array will be * re-used by each invocation. This works because the function is not reentrant. */ -const projectionNodeStack: (LViewData | TNode)[] = []; +const projectionNodeStack: (LView | TNode)[] = []; /** * Walks a tree of TNodes, applying a transformation on the element nodes, either only on the first @@ -107,7 +107,7 @@ const projectionNodeStack: (LViewData | TNode)[] = []; * Insert. */ function walkTNodeTree( - viewToWalk: LViewData, action: WalkTNodeTreeAction, renderer: Renderer3, + viewToWalk: LView, action: WalkTNodeTreeAction, renderer: Renderer3, renderParent: RElement | null, beforeNode?: RNode | null) { const rootTNode = viewToWalk[TVIEW].node as TViewNode; let projectionNodeIndex = -1; @@ -159,7 +159,7 @@ function walkTNodeTree( if (nextTNode === null) { // this last node was projected, we need to get back down to its projection node if (tNode.next === null && (tNode.flags & TNodeFlags.isProjected)) { - currentView = projectionNodeStack[projectionNodeIndex--] as LViewData; + currentView = projectionNodeStack[projectionNodeIndex--] as LView; tNode = projectionNodeStack[projectionNodeIndex--] as TNode; } nextTNode = tNode.next; @@ -184,7 +184,7 @@ function walkTNodeTree( } if (tNode.type === TNodeType.View && currentView[NEXT]) { - currentView = currentView[NEXT] as LViewData; + currentView = currentView[NEXT] as LView; nextTNode = currentView[TVIEW].node; } else { nextTNode = tNode.next; @@ -198,19 +198,19 @@ function walkTNodeTree( /** * Given a current view, finds the nearest component's host (LElement). * - * @param lViewData LViewData for which we want a host element node + * @param lView LView for which we want a host element node * @returns The host node */ -export function findComponentView(lViewData: LViewData): LViewData { - let rootTNode = lViewData[HOST_NODE]; +export function findComponentView(lView: LView): LView { + let rootTNode = lView[HOST_NODE]; while (rootTNode && rootTNode.type === TNodeType.View) { - ngDevMode && assertDefined(lViewData[PARENT], 'viewData.parent'); - lViewData = lViewData[PARENT] !; - rootTNode = lViewData[HOST_NODE]; + ngDevMode && assertDefined(lView[PARENT], 'lView.parent'); + lView = lView[PARENT] !; + rootTNode = lView[HOST_NODE]; } - return lViewData; + return lView; } /** @@ -251,10 +251,10 @@ export function createTextNode(value: any, renderer: Renderer3): RText { * @param beforeNode The node before which elements should be added, if insert mode */ export function addRemoveViewFromContainer( - viewToWalk: LViewData, insertMode: true, beforeNode: RNode | null): void; -export function addRemoveViewFromContainer(viewToWalk: LViewData, insertMode: false): void; + viewToWalk: LView, insertMode: true, beforeNode: RNode | null): void; +export function addRemoveViewFromContainer(viewToWalk: LView, insertMode: false): void; export function addRemoveViewFromContainer( - viewToWalk: LViewData, insertMode: boolean, beforeNode?: RNode | null): void { + viewToWalk: LView, insertMode: boolean, beforeNode?: RNode | null): void { const renderParent = getContainerRenderParent(viewToWalk[TVIEW].node as TViewNode, viewToWalk); ngDevMode && assertNodeType(viewToWalk[TVIEW].node as TNode, TNodeType.View); if (renderParent) { @@ -278,22 +278,22 @@ export function addRemoveViewFromContainer( * * @param rootView The view to destroy */ -export function destroyViewTree(rootView: LViewData): void { +export function destroyViewTree(rootView: LView): void { // If the view has no children, we can clean it up and return early. if (rootView[TVIEW].childIndex === -1) { return cleanUpView(rootView); } - let viewOrContainer: LViewData|LContainer|null = getLViewChild(rootView); + let viewOrContainer: LView|LContainer|null = getLViewChild(rootView); while (viewOrContainer) { - let next: LViewData|LContainer|null = null; + let next: LView|LContainer|null = null; if (viewOrContainer.length >= HEADER_OFFSET) { - // If LViewData, traverse down to child. - const view = viewOrContainer as LViewData; + // If LView, traverse down to child. + const view = viewOrContainer as LView; if (view[TVIEW].childIndex > -1) next = getLViewChild(view); } else { - // If container, traverse down to its first LViewData. + // If container, traverse down to its first LView. const container = viewOrContainer as LContainer; if (container[VIEWS].length) next = container[VIEWS][0]; } @@ -327,7 +327,7 @@ export function destroyViewTree(rootView: LViewData): void { * @param containerIndex The index of the container node, if dynamic */ export function insertView( - lView: LViewData, lContainer: LContainer, parentView: LViewData, index: number, + lView: LView, lContainer: LContainer, parentView: LView, index: number, containerIndex: number) { const views = lContainer[VIEWS]; @@ -374,7 +374,7 @@ export function detachView(lContainer: LContainer, removeIndex: number, detached const views = lContainer[VIEWS]; const viewToDetach = views[removeIndex]; if (removeIndex > 0) { - views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LViewData; + views[removeIndex - 1][NEXT] = viewToDetach[NEXT] as LView; } views.splice(removeIndex, 1); if (!detached) { @@ -405,10 +405,10 @@ export function removeView( destroyLView(view); } -/** Gets the child of the given LViewData */ -export function getLViewChild(viewData: LViewData): LViewData|LContainer|null { - const childIndex = viewData[TVIEW].childIndex; - return childIndex === -1 ? null : viewData[childIndex]; +/** Gets the child of the given LView */ +export function getLViewChild(lView: LView): LView|LContainer|null { + const childIndex = lView[TVIEW].childIndex; + return childIndex === -1 ? null : lView[childIndex]; } /** @@ -417,7 +417,7 @@ export function getLViewChild(viewData: LViewData): LViewData|LContainer|null { * * @param view The view to be destroyed. */ -export function destroyLView(view: LViewData) { +export function destroyLView(view: LView) { const renderer = view[RENDERER]; if (isProceduralRenderer(renderer) && renderer.destroyNode) { walkTNodeTree(view, WalkTNodeTreeAction.Destroy, renderer, null); @@ -439,14 +439,13 @@ export function destroyLView(view: LViewData) { * @param rootView The rootView, so we don't propagate too far up the view tree * @returns The correct parent LViewOrLContainer */ -export function getParentState(state: LViewData | LContainer, rootView: LViewData): LViewData| - LContainer|null { +export function getParentState(state: LView | LContainer, rootView: LView): LView|LContainer|null { let tNode; - if (state.length >= HEADER_OFFSET && (tNode = (state as LViewData) ![HOST_NODE]) && + if (state.length >= HEADER_OFFSET && (tNode = (state as LView) ![HOST_NODE]) && tNode.type === TNodeType.View) { // if it's an embedded view, the state needs to go up to the container, in case the // container has a next - return getLContainer(tNode as TViewNode, state as LViewData) as LContainer; + return getLContainer(tNode as TViewNode, state as LView) as LContainer; } else { // otherwise, use parent view for containers or component views return state[PARENT] === rootView ? null : state[PARENT]; @@ -456,11 +455,11 @@ export function getParentState(state: LViewData | LContainer, rootView: LViewDat /** * Removes all listeners and call all onDestroys in a given view. * - * @param view The LViewData to clean up + * @param view The LView to clean up */ -function cleanUpView(viewOrContainer: LViewData | LContainer): void { - if ((viewOrContainer as LViewData).length >= HEADER_OFFSET) { - const view = viewOrContainer as LViewData; +function cleanUpView(viewOrContainer: LView | LContainer): void { + if ((viewOrContainer as LView).length >= HEADER_OFFSET) { + const view = viewOrContainer as LView; removeListeners(view); executeOnDestroys(view); executePipeOnDestroys(view); @@ -473,32 +472,32 @@ function cleanUpView(viewOrContainer: LViewData | LContainer): void { } /** Removes listeners and unsubscribes from output subscriptions */ -function removeListeners(viewData: LViewData): void { - const cleanup = viewData[TVIEW].cleanup !; +function removeListeners(lView: LView): void { + const cleanup = lView[TVIEW].cleanup !; if (cleanup != null) { for (let i = 0; i < cleanup.length - 1; i += 2) { if (typeof cleanup[i] === 'string') { // This is a listener with the native renderer - const native = readElementValue(viewData[cleanup[i + 1]]); - const listener = viewData[CLEANUP] ![cleanup[i + 2]]; + const native = readElementValue(lView[cleanup[i + 1]]); + const listener = lView[CLEANUP] ![cleanup[i + 2]]; native.removeEventListener(cleanup[i], listener, cleanup[i + 3]); i += 2; } else if (typeof cleanup[i] === 'number') { // This is a listener with renderer2 (cleanup fn can be found by index) - const cleanupFn = viewData[CLEANUP] ![cleanup[i]]; + const cleanupFn = lView[CLEANUP] ![cleanup[i]]; cleanupFn(); } else { // This is a cleanup function that is grouped with the index of its context - const context = viewData[CLEANUP] ![cleanup[i + 1]]; + const context = lView[CLEANUP] ![cleanup[i + 1]]; cleanup[i].call(context); } } - viewData[CLEANUP] = null; + lView[CLEANUP] = null; } } /** Calls onDestroy hooks for this view */ -function executeOnDestroys(view: LViewData): void { +function executeOnDestroys(view: LView): void { const tView = view[TVIEW]; let destroyHooks: HookData|null; if (tView != null && (destroyHooks = tView.destroyHooks) != null) { @@ -507,14 +506,14 @@ function executeOnDestroys(view: LViewData): void { } /** Calls pipe destroy hooks for this view */ -function executePipeOnDestroys(viewData: LViewData): void { - const pipeDestroyHooks = viewData[TVIEW] && viewData[TVIEW].pipeDestroyHooks; +function executePipeOnDestroys(lView: LView): void { + const pipeDestroyHooks = lView[TVIEW] && lView[TVIEW].pipeDestroyHooks; if (pipeDestroyHooks) { - callHooks(viewData !, pipeDestroyHooks); + callHooks(lView !, pipeDestroyHooks); } } -export function getRenderParent(tNode: TNode, currentView: LViewData): RElement|null { +export function getRenderParent(tNode: TNode, currentView: LView): RElement|null { if (canInsertNativeNode(tNode, currentView)) { // If we are asked for a render parent of the root component we need to do low-level DOM // operation as LTree doesn't exist above the topmost host node. We might need to find a render @@ -565,7 +564,7 @@ function canInsertNativeChildOfElement(tNode: TNode): boolean { * and * the container itself has its render parent determined. */ -function canInsertNativeChildOfView(viewTNode: TViewNode, view: LViewData): boolean { +function canInsertNativeChildOfView(viewTNode: TViewNode, view: LView): boolean { // Because we are inserting into a `View` the `View` may be disconnected. const container = getLContainer(viewTNode, view) !; if (container == null || container[RENDER_PARENT] == null) { @@ -597,7 +596,7 @@ function canInsertNativeChildOfView(viewTNode: TViewNode, view: LViewData): bool * @param currentView Current LView being processed. * @return boolean Whether the node should be inserted now (or delayed until later). */ -export function canInsertNativeNode(tNode: TNode, currentView: LViewData): boolean { +export function canInsertNativeNode(tNode: TNode, currentView: LView): boolean { let currentNode = tNode; let parent: TNode|null = tNode.parent; @@ -659,7 +658,7 @@ export function nativeNextSibling(renderer: Renderer3, node: RNode): RNode|null * @returns Whether or not the child was appended */ export function appendChild( - childEl: RNode | null = null, childTNode: TNode, currentView: LViewData): boolean { + childEl: RNode | null = null, childTNode: TNode, currentView: LView): boolean { if (childEl !== null && canInsertNativeNode(childTNode, currentView)) { const renderer = currentView[RENDERER]; const parentEl = getParentNative(childTNode, currentView); @@ -700,9 +699,9 @@ function getHighestElementContainer(ngContainer: TNode): TNode { return ngContainer; } -export function getBeforeNodeForView(index: number, views: LViewData[], containerNative: RComment) { +export function getBeforeNodeForView(index: number, views: LView[], containerNative: RComment) { if (index + 1 < views.length) { - const view = views[index + 1] as LViewData; + const view = views[index + 1] as LView; const viewTNode = view[HOST_NODE] as TViewNode; return viewTNode.child ? getNativeByTNode(viewTNode.child, view) : containerNative; } else { @@ -718,8 +717,7 @@ export function getBeforeNodeForView(index: number, views: LViewData[], containe * @param currentView The current LView * @returns Whether or not the child was removed */ -export function removeChild( - childTNode: TNode, childEl: RNode | null, currentView: LViewData): boolean { +export function removeChild(childTNode: TNode, childEl: RNode | null, currentView: LView): boolean { // 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; @@ -741,8 +739,8 @@ export function removeChild( * @param projectionView Projection view (view above current) */ export function appendProjectedNode( - projectedTNode: TNode, tProjectionNode: TNode, currentView: LViewData, - projectionView: LViewData): void { + projectedTNode: TNode, tProjectionNode: TNode, currentView: LView, + projectionView: LView): void { const native = getNativeByTNode(projectedTNode, projectionView); appendChild(native, tProjectionNode, currentView); diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index d29aae0a63..2267de9360 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -10,9 +10,9 @@ import {PipeTransform} from '../change_detection/pipe_transform'; import {load, store} from './instructions'; import {PipeDef, PipeDefList} from './interfaces/definition'; -import {HEADER_OFFSET} from './interfaces/view'; +import {HEADER_OFFSET, TVIEW} from './interfaces/view'; import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunctionV} from './pure_function'; -import {getTView} from './state'; +import {getLView} from './state'; /** * Create a pipe. @@ -22,7 +22,7 @@ import {getTView} from './state'; * @returns T the instance of the pipe. */ export function pipe(index: number, pipeName: string): any { - const tView = getTView(); + const tView = getLView()[TVIEW]; let pipeDef: PipeDef; const adjustedIndex = index + HEADER_OFFSET; @@ -152,5 +152,5 @@ export function pipeBindV(index: number, slotOffset: number, values: any[]): any } function isPure(index: number): boolean { - return (>getTView().data[index + HEADER_OFFSET]).pure; + return (>getLView()[TVIEW].data[index + HEADER_OFFSET]).pure; } diff --git a/packages/core/src/render3/players.ts b/packages/core/src/render3/players.ts index 74bee39ad1..feb239501e 100644 --- a/packages/core/src/render3/players.ts +++ b/packages/core/src/render3/players.ts @@ -36,9 +36,9 @@ export function addPlayer( } const element = context.native as HTMLElement; - const lViewData = context.lViewData; + const lView = context.lView; const playerContext = getOrCreatePlayerContext(element, context) !; - const rootContext = getRootContext(lViewData); + const rootContext = getRootContext(lView); addPlayerInternal(playerContext, rootContext, element, player, 0, ref); scheduleTick(rootContext, RootContextFlags.FlushPlayers); } @@ -60,7 +60,7 @@ export function getPlayers(ref: ComponentInstance | DirectiveInstance | HTMLElem return []; } - const stylingContext = getStylingContext(context.nodeIndex - HEADER_OFFSET, context.lViewData); + const stylingContext = getStylingContext(context.nodeIndex - HEADER_OFFSET, context.lView); const playerContext = stylingContext ? getPlayerContext(stylingContext) : null; return playerContext ? getPlayersInternal(playerContext) : []; } diff --git a/packages/core/src/render3/pure_function.ts b/packages/core/src/render3/pure_function.ts index 871042411b..562b6b0d1e 100644 --- a/packages/core/src/render3/pure_function.ts +++ b/packages/core/src/render3/pure_function.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, getBinding, updateBinding} from './instructions'; -import {getBindingRoot, getCreationMode} from './state'; +import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, getBinding, updateBinding} from './bindings'; +import {getBindingRoot, getCreationMode, getLView} from './state'; + /** @@ -40,9 +41,10 @@ import {getBindingRoot, getCreationMode} from './state'; export function pureFunction0(slotOffset: number, pureFn: () => T, thisArg?: any): T { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; + const lView = getLView(); return getCreationMode() ? - updateBinding(bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) : - getBinding(bindingIndex); + updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) : + getBinding(lView, bindingIndex); } /** @@ -58,10 +60,11 @@ export function pureFunction0(slotOffset: number, pureFn: () => T, thisArg?: export function pureFunction1( slotOffset: number, pureFn: (v: any) => any, exp: any, thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings + const lView = getLView(); const bindingIndex = getBindingRoot() + slotOffset; - return bindingUpdated(bindingIndex, exp) ? - updateBinding(bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) : - getBinding(bindingIndex + 1); + return bindingUpdated(lView, bindingIndex, exp) ? + updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) : + getBinding(lView, bindingIndex + 1); } /** @@ -80,10 +83,12 @@ export function pureFunction2( thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - return bindingUpdated2(bindingIndex, exp1, exp2) ? + const lView = getLView(); + return bindingUpdated2(lView, bindingIndex, exp1, exp2) ? updateBinding( - bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) : - getBinding(bindingIndex + 2); + lView, bindingIndex + 2, + thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) : + getBinding(lView, bindingIndex + 2); } /** @@ -103,11 +108,12 @@ export function pureFunction3( thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - return bindingUpdated3(bindingIndex, exp1, exp2, exp3) ? + const lView = getLView(); + return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ? updateBinding( - bindingIndex + 3, + lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) : - getBinding(bindingIndex + 3); + getBinding(lView, bindingIndex + 3); } /** @@ -128,11 +134,12 @@ export function pureFunction4( exp3: any, exp4: any, thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - return bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4) ? + const lView = getLView(); + return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ? updateBinding( - bindingIndex + 4, + lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) : - getBinding(bindingIndex + 4); + getBinding(lView, bindingIndex + 4); } /** @@ -154,12 +161,13 @@ export function pureFunction5( exp2: any, exp3: any, exp4: any, exp5: any, thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); - return bindingUpdated(bindingIndex + 4, exp5) || different ? + const lView = getLView(); + const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); + return bindingUpdated(lView, bindingIndex + 4, exp5) || different ? updateBinding( - bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) : - pureFn(exp1, exp2, exp3, exp4, exp5)) : - getBinding(bindingIndex + 5); + lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) : + pureFn(exp1, exp2, exp3, exp4, exp5)) : + getBinding(lView, bindingIndex + 5); } /** @@ -182,12 +190,14 @@ export function pureFunction6( exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); - return bindingUpdated2(bindingIndex + 4, exp5, exp6) || different ? + const lView = getLView(); + const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); + return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ? updateBinding( - bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) : - pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) : - getBinding(bindingIndex + 6); + lView, bindingIndex + 6, thisArg ? + pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) : + pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) : + getBinding(lView, bindingIndex + 6); } /** @@ -212,13 +222,14 @@ export function pureFunction7( exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - let different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); - return bindingUpdated3(bindingIndex + 4, exp5, exp6, exp7) || different ? + const lView = getLView(); + let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); + return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ? updateBinding( - bindingIndex + 7, thisArg ? + lView, bindingIndex + 7, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) : pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) : - getBinding(bindingIndex + 7); + getBinding(lView, bindingIndex + 7); } /** @@ -245,13 +256,14 @@ export function pureFunction8( thisArg?: any): any { // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings const bindingIndex = getBindingRoot() + slotOffset; - const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4); - return bindingUpdated4(bindingIndex + 4, exp5, exp6, exp7, exp8) || different ? + const lView = getLView(); + const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); + return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ? updateBinding( - bindingIndex + 8, thisArg ? + lView, bindingIndex + 8, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) : pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) : - getBinding(bindingIndex + 8); + getBinding(lView, bindingIndex + 8); } /** @@ -272,9 +284,10 @@ export function pureFunctionV( // TODO(kara): use bindingRoot instead of bindingStartIndex when implementing host bindings let bindingIndex = getBindingRoot() + slotOffset; let different = false; + const lView = getLView(); for (let i = 0; i < exps.length; i++) { - bindingUpdated(bindingIndex++, exps[i]) && (different = true); + bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true); } - return different ? updateBinding(bindingIndex, pureFn.apply(thisArg, exps)) : - getBinding(bindingIndex); + return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) : + getBinding(lView, bindingIndex); } diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index cdb0907025..d0ea61c539 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -17,7 +17,7 @@ import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref'; import {Type} from '../type'; import {getSymbolIterator} from '../util'; -import {assertDefined, assertEqual} from './assert'; +import {assertDefined, assertEqual, assertPreviousIsParent} from './assert'; import {getNodeInjectable, locateDirectiveOrProvider} from './di'; import {NG_ELEMENT_ID} from './fields'; import {store, storeCleanupWithContext} from './instructions'; @@ -25,8 +25,8 @@ import {unusedValueExportToPlacateAjd as unused1} from './interfaces/definition' import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node'; import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query'; -import {LViewData, TVIEW} from './interfaces/view'; -import {assertPreviousIsParent, getOrCreateCurrentQueries, getViewData} from './state'; +import {LView, TVIEW} from './interfaces/view'; +import {getIsParent, getLView, getOrCreateCurrentQueries} from './state'; import {flatten, isContentQueryHost} from './util'; import {createElementRef, createTemplateRef} from './view_engine_compatibility'; @@ -245,7 +245,7 @@ function getIdxOfMatchingSelector(tNode: TNode, selector: string): number|null { // TODO: "read" should be an AbstractType (FW-486) -function queryByReadToken(read: any, tNode: TNode, currentView: LViewData): any { +function queryByReadToken(read: any, tNode: TNode, currentView: LView): any { const factoryFn = (read as any)[NG_ELEMENT_ID]; if (typeof factoryFn === 'function') { return factoryFn(); @@ -259,7 +259,7 @@ function queryByReadToken(read: any, tNode: TNode, currentView: LViewData): any return null; } -function queryByTNodeType(tNode: TNode, currentView: LViewData): any { +function queryByTNodeType(tNode: TNode, currentView: LView): any { if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) { return createElementRef(ViewEngine_ElementRef, tNode, currentView); } @@ -270,7 +270,7 @@ function queryByTNodeType(tNode: TNode, currentView: LViewData): any { } function queryByTemplateRef( - templateRefToken: ViewEngine_TemplateRef, tNode: TNode, currentView: LViewData, + templateRefToken: ViewEngine_TemplateRef, tNode: TNode, currentView: LView, read: any): any { const templateRefResult = (templateRefToken as any)[NG_ELEMENT_ID](); if (read) { @@ -279,7 +279,7 @@ function queryByTemplateRef( return templateRefResult; } -function queryRead(tNode: TNode, currentView: LViewData, read: any, matchingIdx: number): any { +function queryRead(tNode: TNode, currentView: LView, read: any, matchingIdx: number): any { if (read) { return queryByReadToken(read, tNode, currentView); } @@ -294,7 +294,7 @@ function queryRead(tNode: TNode, currentView: LViewData, read: any, matchingIdx: function add( query: LQuery| null, tNode: TElementNode | TContainerNode | TElementContainerNode) { - const currentView = getViewData(); + const currentView = getLView(); while (query) { const predicate = query.predicate; @@ -455,11 +455,11 @@ export function query( memoryIndex: number | null, predicate: Type| string[], descend?: boolean, // TODO: "read" should be an AbstractType (FW-486) read?: any): QueryList { - ngDevMode && assertPreviousIsParent(); + ngDevMode && assertPreviousIsParent(getIsParent()); const queryList = new QueryList(); const queries = getOrCreateCurrentQueries(LQueries_); queries.track(queryList, predicate, descend, read); - storeCleanupWithContext(null, queryList, queryList.destroy); + storeCleanupWithContext(getLView(), queryList, queryList.destroy); if (memoryIndex != null) { store(memoryIndex, queryList); } diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 38417908dd..5d18c1fbe9 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -6,58 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ -import {Sanitizer} from '../sanitization/security'; - -import {assertDefined, assertEqual} from './assert'; +import {assertDefined} from './assert'; import {executeHooks} from './hooks'; import {TElementNode, TNode, TNodeFlags, TViewNode} from './interfaces/node'; import {LQueries} from './interfaces/query'; -import {Renderer3, RendererFactory3} from './interfaces/renderer'; -import {BINDING_INDEX, CLEANUP, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LViewData, LViewFlags, OpaqueViewState, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, TView} from './interfaces/view'; -import {assertDataInRangeInternal, isContentQueryHost} from './util'; +import {BINDING_INDEX, CONTEXT, DECLARATION_VIEW, FLAGS, HOST_NODE, LView, LViewFlags, OpaqueViewState, QUERIES, TVIEW} from './interfaces/view'; +import {isContentQueryHost} from './util'; -/** - * This property gets set before entering a template. - * - * This renderer can be one of two varieties of Renderer3: - * - * - ObjectedOrientedRenderer3 - * - * This is the native browser API style, e.g. operations are methods on individual objects - * like HTMLElement. With this style, no additional code is needed as a facade (reducing payload - * size). - * - * - ProceduralRenderer3 - * - * In non-native browser environments (e.g. platforms such as web-workers), this is the facade - * that enables element manipulation. This also facilitates backwards compatibility with - * Renderer2. - */ -let renderer: Renderer3; -export function getRenderer(): Renderer3 { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return renderer; -} - -export function setRenderer(r: Renderer3): void { - renderer = r; -} - -let rendererFactory: RendererFactory3; - -export function getRendererFactory(): RendererFactory3 { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return rendererFactory; -} - -export function getCurrentSanitizer(): Sanitizer|null { - return viewData && viewData[SANITIZER]; -} /** * Store the element depth count. This is used to identify the root elements of the template - * so that we can than attach `LViewData` to only those elements. + * so that we can than attach `LView` to only those elements. */ let elementDepthCount !: number; @@ -142,19 +102,8 @@ export function disableBindings(): void { bindingsEnabled = false; } -/** - * Returns the current OpaqueViewState instance. - * - * Used in conjunction with the restoreView() instruction to save a snapshot - * of the current view and restore it when listeners are invoked. This allows - * walking the declaration view tree in listeners to get vars from parent views. - */ -export function getCurrentView(): OpaqueViewState { - return viewData as any as OpaqueViewState; -} - -export function _getViewData(): LViewData { - return viewData; +export function getLView(): LView { + return lView; } /** @@ -167,7 +116,7 @@ export function _getViewData(): LViewData { * @param viewToRestore The OpaqueViewState instance to restore. */ export function restoreView(viewToRestore: OpaqueViewState) { - contextViewData = viewToRestore as any as LViewData; + contextLView = viewToRestore as any as LView; } /** Used to set the parent property when nodes are created and track query results. */ @@ -182,9 +131,9 @@ export function setPreviousOrParentTNode(tNode: TNode) { previousOrParentTNode = tNode; } -export function setTNodeAndViewData(tNode: TNode, view: LViewData) { +export function setTNodeAndViewData(tNode: TNode, view: LView) { previousOrParentTNode = tNode; - viewData = view; + lView = view; } /** @@ -203,24 +152,6 @@ export function setIsParent(value: boolean): void { isParent = value; } -let tView: TView; - -export function getTView(): TView { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return tView; -} - -let currentQueries: LQueries|null; - -export function getCurrentQueries(): LQueries|null { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return currentQueries; -} - -export function setCurrentQueries(queries: LQueries | null): void { - currentQueries = queries; -} - /** * Query instructions can ask for "current queries" in 2 different cases: * - when creating view queries (at the root of a component view, before any node is created - in @@ -230,15 +161,17 @@ export function setCurrentQueries(queries: LQueries | null): void { */ export function getOrCreateCurrentQueries( QueryType: {new (parent: null, shallow: null, deep: null): LQueries}): LQueries { + const lView = getLView(); + let currentQueries = lView[QUERIES]; // if this is the first content query on a node, any existing LQueries needs to be cloned // in subsequent template passes, the cloning occurs before directive instantiation. - if (previousOrParentTNode && previousOrParentTNode !== viewData[HOST_NODE] && + if (previousOrParentTNode && previousOrParentTNode !== lView[HOST_NODE] && !isContentQueryHost(previousOrParentTNode)) { - currentQueries && (currentQueries = currentQueries.clone()); + currentQueries && (currentQueries = lView[QUERIES] = currentQueries.clone()); previousOrParentTNode.flags |= TNodeFlags.hasContentQuery; } - return currentQueries || (currentQueries = new QueryType(null, null, null)); + return currentQueries || (lView[QUERIES] = new QueryType(null, null, null)); } /** @@ -257,17 +190,7 @@ export function getCreationMode(): boolean { * An array of nodes (text, element, container, etc), pipes, their bindings, and * any local variables that need to be stored between invocations. */ -let viewData: LViewData; - -/** - * Internal function that returns the current LViewData instance. - * - * The getCurrentView() instruction should be used for anything public. - */ -export function getViewData(): LViewData { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return viewData; -} +let lView: LView; /** * The last viewData retrieved by nextContext(). @@ -275,21 +198,13 @@ export function getViewData(): LViewData { * * e.g. const inner = x().$implicit; const outer = x().$implicit; */ -let contextViewData: LViewData = null !; +let contextLView: LView = null !; -export function getContextViewData(): LViewData { +export function getContextLView(): LView { // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return contextViewData; + return contextLView; } -export function getCleanup(view: LViewData): any[] { - // top level variables should not be exported for performance reasons (PERF_NOTES.md) - return view[CLEANUP] || (view[CLEANUP] = []); -} - -export function getTViewCleanup(view: LViewData): any[] { - return view[TVIEW].cleanup || (view[TVIEW].cleanup = []); -} /** * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error. * @@ -345,33 +260,29 @@ export function setBindingRoot(value: number) { * @param host Element to which the View is a child of * @returns the previous state; */ -export function enterView( - newView: LViewData, hostTNode: TElementNode | TViewNode | null): LViewData { - const oldView: LViewData = viewData; - tView = newView && newView[TVIEW]; +export function enterView(newView: LView, hostTNode: TElementNode | TViewNode | null): LView { + const oldView = lView; + if (newView) { + const tView = newView[TVIEW]; - creationMode = newView && (newView[FLAGS] & LViewFlags.CreationMode) === LViewFlags.CreationMode; - firstTemplatePass = newView && tView.firstTemplatePass; - bindingRootIndex = newView && tView.bindingStartIndex; - rendererFactory = newView && newView[RENDERER_FACTORY]; - renderer = newView && newView[RENDERER]; + creationMode = (newView[FLAGS] & LViewFlags.CreationMode) === LViewFlags.CreationMode; + firstTemplatePass = tView.firstTemplatePass; + bindingRootIndex = tView.bindingStartIndex; + } previousOrParentTNode = hostTNode !; isParent = true; - viewData = contextViewData = newView; - oldView && (oldView[QUERIES] = currentQueries); - currentQueries = newView && newView[QUERIES]; - + lView = contextLView = newView; return oldView; } export function nextContextImpl(level: number = 1): T { - contextViewData = walkUpViews(level, contextViewData !); - return contextViewData[CONTEXT] as T; + contextLView = walkUpViews(level, contextLView !); + return contextLView[CONTEXT] as T; } -function walkUpViews(nestingLevel: number, currentView: LViewData): LViewData { +function walkUpViews(nestingLevel: number, currentView: LView): LView { while (nestingLevel > 0) { ngDevMode && assertDefined( currentView[DECLARATION_VIEW], @@ -400,34 +311,16 @@ export function resetComponentState() { * @param creationOnly An optional boolean to indicate that the view was processed in creation mode * only, i.e. the first update will be done later. Only possible for dynamically created views. */ -export function leaveView(newView: LViewData, creationOnly?: boolean): void { +export function leaveView(newView: LView, creationOnly?: boolean): void { + const tView = lView[TVIEW]; if (!creationOnly) { if (!checkNoChangesMode) { - executeHooks(viewData, tView.viewHooks, tView.viewCheckHooks, creationMode); + executeHooks(lView, tView.viewHooks, tView.viewCheckHooks, creationMode); } // Views are clean and in update mode after being checked, so these bits are cleared - viewData[FLAGS] &= ~(LViewFlags.CreationMode | LViewFlags.Dirty); + lView[FLAGS] &= ~(LViewFlags.CreationMode | LViewFlags.Dirty); } - viewData[FLAGS] |= LViewFlags.RunInit; - viewData[BINDING_INDEX] = tView.bindingStartIndex; + lView[FLAGS] |= LViewFlags.RunInit; + lView[BINDING_INDEX] = tView.bindingStartIndex; enterView(newView, null); } - -export function assertPreviousIsParent() { - assertEqual(isParent, true, 'previousOrParentTNode should be a parent'); -} - -export function assertHasParent() { - assertDefined(previousOrParentTNode.parent, 'previousOrParentTNode should have a parent'); -} - -export function assertDataInRange(index: number, arr?: any[]) { - if (arr == null) arr = viewData; - assertDataInRangeInternal(index, arr || viewData); -} - -export function assertDataNext(index: number, arr?: any[]) { - if (arr == null) arr = viewData; - assertEqual( - arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`); -} diff --git a/packages/core/src/render3/styling/class_and_style_bindings.ts b/packages/core/src/render3/styling/class_and_style_bindings.ts index 55f0290111..cd4d687e7b 100644 --- a/packages/core/src/render3/styling/class_and_style_bindings.ts +++ b/packages/core/src/render3/styling/class_and_style_bindings.ts @@ -10,7 +10,7 @@ import {InitialStylingFlags} from '../interfaces/definition'; import {BindingStore, BindingType, Player, PlayerBuilder, PlayerFactory, PlayerIndex} from '../interfaces/player'; import {Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer'; import {InitialStyles, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling'; -import {LViewData, RootContext} from '../interfaces/view'; +import {LView, RootContext} from '../interfaces/view'; import {NO_CHANGE} from '../tokens'; import {getRootContext} from '../util'; @@ -479,7 +479,7 @@ export function updateClassProp( * @returns number the total amount of players that got queued for animation (if any) */ export function renderStyleAndClassBindings( - context: StylingContext, renderer: Renderer3, rootOrView: RootContext | LViewData, + context: StylingContext, renderer: Renderer3, rootOrView: RootContext | LView, isFirstRender: boolean, classesStore?: BindingStore | null, stylesStore?: BindingStore | null): number { let totalPlayersQueued = 0; diff --git a/packages/core/src/render3/styling/util.ts b/packages/core/src/render3/styling/util.ts index 0d6909e569..8c88b1972b 100644 --- a/packages/core/src/render3/styling/util.ts +++ b/packages/core/src/render3/styling/util.ts @@ -14,7 +14,7 @@ import {LContext} from '../interfaces/context'; import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/player'; import {RElement} from '../interfaces/renderer'; import {InitialStyles, StylingContext, StylingIndex} from '../interfaces/styling'; -import {FLAGS, HEADER_OFFSET, HOST, LViewData, RootContext} from '../interfaces/view'; +import {FLAGS, HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view'; import {getTNode} from '../util'; import {CorePlayerHandler} from './core_player_handler'; @@ -59,20 +59,20 @@ export function allocStylingContext( * @param index Index of the style allocation. See: `elementStyling`. * @param viewData The view to search for the styling context */ -export function getStylingContext(index: number, viewData: LViewData): StylingContext { +export function getStylingContext(index: number, viewData: LView): StylingContext { let storageIndex = index + HEADER_OFFSET; - let slotValue: LContainer|LViewData|StylingContext|RElement = viewData[storageIndex]; - let wrapper: LContainer|LViewData|StylingContext = viewData; + let slotValue: LContainer|LView|StylingContext|RElement = viewData[storageIndex]; + let wrapper: LContainer|LView|StylingContext = viewData; while (Array.isArray(slotValue)) { wrapper = slotValue; - slotValue = slotValue[HOST] as LViewData | StylingContext | RElement; + slotValue = slotValue[HOST] as LView | StylingContext | RElement; } if (isStylingContext(wrapper)) { return wrapper as StylingContext; } else { - // This is an LViewData or an LContainer + // This is an LView or an LContainer const stylingTemplate = getTNode(index, viewData).stylingTemplate; if (wrapper !== viewData) { @@ -85,8 +85,8 @@ export function getStylingContext(index: number, viewData: LViewData): StylingCo } } -function isStylingContext(value: LViewData | LContainer | StylingContext) { - // Not an LViewData or an LContainer +function isStylingContext(value: LView | LContainer | StylingContext) { + // Not an LView or an LContainer return typeof value[FLAGS] !== 'number' && typeof value[ACTIVE_INDEX] !== 'number'; } @@ -158,8 +158,8 @@ export function getOrCreatePlayerContext(target: {}, context?: LContext | null): return null; } - const {lViewData, nodeIndex} = context; - const stylingContext = getStylingContext(nodeIndex - HEADER_OFFSET, lViewData); + const {lView, nodeIndex} = context; + const stylingContext = getStylingContext(nodeIndex - HEADER_OFFSET, lView); return getPlayerContext(stylingContext) || allocPlayerContext(stylingContext); } diff --git a/packages/core/src/render3/util.ts b/packages/core/src/render3/util.ts index 4af3f93426..f0c1e82344 100644 --- a/packages/core/src/render3/util.ts +++ b/packages/core/src/render3/util.ts @@ -6,10 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {devModeEqual} from '../change_detection/change_detection_util'; import {global} from '../util'; -import {assertDefined, assertLessThan} from './assert'; +import {assertDataInRange, assertDefined} from './assert'; import {ACTIVE_INDEX, LContainer} from './interfaces/container'; import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context'; import {ComponentDef, DirectiveDef} from './interfaces/definition'; @@ -17,7 +16,7 @@ import {NO_PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFl import {TContainerNode, TElementNode, TNode, TNodeFlags} from './interfaces/node'; import {RComment, RElement, RText} from './interfaces/renderer'; import {StylingContext} from './interfaces/styling'; -import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LViewData, LViewFlags, PARENT, RootContext, TData, TVIEW} from './interfaces/view'; +import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LView, LViewFlags, PARENT, RootContext, TData, TVIEW, TView} from './interfaces/view'; @@ -26,10 +25,7 @@ import {CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, LViewD * * Constraints are relaxed in checkNoChanges mode. See `devModeEqual` for details. */ -export function isDifferent(a: any, b: any, checkNoChangesMode: boolean): boolean { - if (ngDevMode && checkNoChangesMode) { - return !devModeEqual(a, b); - } +export function isDifferent(a: any, b: any): boolean { // NaN is the only value that is not equal to itself so the first // test checks if both a and b are not NaN return !(a !== a && b !== b) && a !== b; @@ -67,29 +63,24 @@ export function flatten(list: any[]): any[] { return result; } -/** Retrieves a value from any `LViewData` or `TData`. */ -export function loadInternal(index: number, arr: LViewData | TData): T { - ngDevMode && assertDataInRangeInternal(index + HEADER_OFFSET, arr); - return arr[index + HEADER_OFFSET]; -} - -export function assertDataInRangeInternal(index: number, arr: any[]) { - assertLessThan(index, arr ? arr.length : 0, 'index expected to be a valid data index'); +/** Retrieves a value from any `LView` or `TData`. */ +export function loadInternal(view: LView | TData, index: number): T { + ngDevMode && assertDataInRange(view, index + HEADER_OFFSET); + return view[index + HEADER_OFFSET]; } /** - * Takes the value of a slot in `LViewData` and returns the element node. + * Takes the value of a slot in `LView` and returns the element node. * * Normally, element nodes are stored flat, but if the node has styles/classes on it, * it might be wrapped in a styling context. Or if that node has a directive that injects * ViewContainerRef, it may be wrapped in an LContainer. Or if that node is a component, - * it will be wrapped in LViewData. It could even have all three, so we keep looping + * it will be wrapped in LView. It could even have all three, so we keep looping * until we find something that isn't an array. * - * @param value The initial value in `LViewData` + * @param value The initial value in `LView` */ -export function readElementValue(value: RElement | StylingContext | LContainer | LViewData): - RElement { +export function readElementValue(value: RElement | StylingContext | LContainer | LView): RElement { while (Array.isArray(value)) { value = value[HOST] as any; } @@ -100,20 +91,20 @@ export function readElementValue(value: RElement | StylingContext | LContainer | * 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]); +export function getNativeByIndex(index: number, lView: LView): RElement { + return readElementValue(lView[index + HEADER_OFFSET]); } -export function getNativeByTNode(tNode: TNode, hostView: LViewData): RElement|RText|RComment { +export function getNativeByTNode(tNode: TNode, hostView: LView): RElement|RText|RComment { return readElementValue(hostView[tNode.index]); } -export function getTNode(index: number, view: LViewData): TNode { +export function getTNode(index: number, view: LView): TNode { return view[TVIEW].data[index + HEADER_OFFSET] as TNode; } -export function getComponentViewByIndex(nodeIndex: number, hostView: LViewData): LViewData { - // Could be an LViewData or an LContainer. If LContainer, unwrap to find LViewData. +export function getComponentViewByIndex(nodeIndex: number, hostView: LView): LView { + // Could be an LView or an LContainer. If LContainer, unwrap to find LView. const slotValue = hostView[nodeIndex]; return slotValue.length >= HEADER_OFFSET ? slotValue : slotValue[HOST]; } @@ -135,26 +126,26 @@ export function isLContainer(value: RElement | RComment | LContainer | StylingCo return Array.isArray(value) && typeof value[ACTIVE_INDEX] === 'number'; } -export function isRootView(target: LViewData): boolean { +export function isRootView(target: LView): boolean { return (target[FLAGS] & LViewFlags.IsRoot) !== 0; } /** - * Retrieve the root view from any component by walking the parent `LViewData` until - * reaching the root `LViewData`. + * Retrieve the root view from any component by walking the parent `LView` until + * reaching the root `LView`. * * @param component any component */ -export function getRootView(target: LViewData | {}): LViewData { +export function getRootView(target: LView | {}): LView { ngDevMode && assertDefined(target, 'component'); - let lViewData = Array.isArray(target) ? (target as LViewData) : readPatchedLViewData(target) !; - while (lViewData && !(lViewData[FLAGS] & LViewFlags.IsRoot)) { - lViewData = lViewData[PARENT] !; + let lView = Array.isArray(target) ? (target as LView) : readPatchedLView(target) !; + while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { + lView = lView[PARENT] !; } - return lViewData; + return lView; } -export function getRootContext(viewOrComponent: LViewData | {}): RootContext { +export function getRootContext(viewOrComponent: LView | {}): RootContext { const rootView = getRootView(viewOrComponent); ngDevMode && assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?'); @@ -165,14 +156,14 @@ export function getRootContext(viewOrComponent: LViewData | {}): RootContext { * Returns the monkey-patch value data present on the target (which could be * a component, directive or a DOM node). */ -export function readPatchedData(target: any): LViewData|LContext|null { +export function readPatchedData(target: any): LView|LContext|null { return target[MONKEY_PATCH_KEY_NAME]; } -export function readPatchedLViewData(target: any): LViewData|null { +export function readPatchedLView(target: any): LView|null { const value = readPatchedData(target); if (value) { - return Array.isArray(value) ? value : (value as LContext).lViewData; + return Array.isArray(value) ? value : (value as LContext).lView; } return null; } @@ -195,11 +186,10 @@ export function getParentInjectorViewOffset(parentLocation: RelativeInjectorLoca * injector. * * @param location The location of the parent injector, which contains the view offset - * @param startView The LViewData instance from which to start walking up the view tree - * @returns The LViewData instance that contains the parent injector + * @param startView The LView instance from which to start walking up the view tree + * @returns The LView instance that contains the parent injector */ -export function getParentInjectorView( - location: RelativeInjectorLocation, startView: LViewData): LViewData { +export function getParentInjectorView(location: RelativeInjectorLocation, startView: LView): LView { let viewOffset = getParentInjectorViewOffset(location); let parentView = startView; // For most cases, the parent injector can be found on the host node (e.g. for component @@ -218,12 +208,12 @@ export function getParentInjectorView( * then walks up the declaration view tree until the TNode of the parent injector is found. * * @param location The location of the parent injector, which contains the view offset - * @param startView The LViewData instance from which to start walking up the view tree + * @param startView The LView instance from which to start walking up the view tree * @param startTNode The TNode instance of the starting element * @returns The TNode of the parent injector */ export function getParentInjectorTNode( - location: RelativeInjectorLocation, startView: LViewData, startTNode: TNode): TElementNode| + location: RelativeInjectorLocation, startView: LView, startTNode: TNode): TElementNode| TContainerNode|null { if (startTNode.parent && startTNode.parent.injectorIndex !== -1) { // view offset is 0 diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index 9246335101..422f6dba8e 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -25,10 +25,10 @@ import {RenderFlags} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node'; import {LQueries} from './interfaces/query'; import {RComment, RElement, Renderer3, isProceduralRenderer} from './interfaces/renderer'; -import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TView} from './interfaces/view'; +import {CONTEXT, HOST_NODE, LView, QUERIES, RENDERER, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation'; -import {getPreviousOrParentTNode, getRenderer, getViewData} from './state'; +import {getLView, getPreviousOrParentTNode} from './state'; import {getComponentViewByIndex, getNativeByTNode, getParentInjectorTNode, getParentInjectorView, hasParentInjector, isComponent, isLContainer, isRootView} from './util'; import {ViewRef} from './view_ref'; @@ -41,7 +41,7 @@ import {ViewRef} from './view_ref'; */ export function injectElementRef(ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_ElementRef { - return createElementRef(ElementRefToken, getPreviousOrParentTNode(), getViewData()); + return createElementRef(ElementRefToken, getPreviousOrParentTNode(), getLView()); } let R3ElementRef: {new (native: RElement | RComment): ViewEngine_ElementRef}; @@ -56,7 +56,7 @@ let R3ElementRef: {new (native: RElement | RComment): ViewEngine_ElementRef}; */ export function createElementRef( ElementRefToken: typeof ViewEngine_ElementRef, tNode: TNode, - view: LViewData): ViewEngine_ElementRef { + view: LView): ViewEngine_ElementRef { if (!R3ElementRef) { // TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug R3ElementRef = class ElementRef_ extends ElementRefToken {}; @@ -66,7 +66,7 @@ export function createElementRef( let R3TemplateRef: { new ( - _declarationParentView: LViewData, elementRef: ViewEngine_ElementRef, _tView: TView, + _declarationParentView: LView, elementRef: ViewEngine_ElementRef, _tView: TView, _renderer: Renderer3, _queries: LQueries | null, _injectorIndex: number): ViewEngine_TemplateRef }; @@ -80,7 +80,7 @@ export function injectTemplateRef( TemplateRefToken: typeof ViewEngine_TemplateRef, ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_TemplateRef|null { return createTemplateRef( - TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), getViewData()); + TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), getLView()); } /** @@ -94,12 +94,12 @@ export function injectTemplateRef( */ export function createTemplateRef( TemplateRefToken: typeof ViewEngine_TemplateRef, ElementRefToken: typeof ViewEngine_ElementRef, - hostTNode: TNode, hostView: LViewData): ViewEngine_TemplateRef|null { + hostTNode: TNode, hostView: LView): ViewEngine_TemplateRef|null { if (!R3TemplateRef) { // TODO: Fix class name, should be TemplateRef, but there appears to be a rollup bug R3TemplateRef = class TemplateRef_ extends TemplateRefToken { constructor( - private _declarationParentView: LViewData, readonly elementRef: ViewEngine_ElementRef, + private _declarationParentView: LView, readonly elementRef: ViewEngine_ElementRef, private _tView: TView, private _renderer: Renderer3, private _queries: LQueries|null, private _injectorIndex: number) { super(); @@ -107,7 +107,7 @@ export function createTemplateRef( createEmbeddedView( context: T, container?: LContainer, - hostTNode?: TElementNode|TContainerNode|TElementContainerNode, hostView?: LViewData, + hostTNode?: TElementNode|TContainerNode|TElementContainerNode, hostView?: LView, index?: number): viewEngine_EmbeddedViewRef { const lView = createEmbeddedViewAndNode( this._tView, context, this._declarationParentView, this._renderer, this._queries, @@ -128,7 +128,7 @@ export function createTemplateRef( ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated'); return new R3TemplateRef( hostView, createElementRef(ElementRefToken, hostTNode, hostView), hostTNode.tViews as TView, - getRenderer(), hostContainer[QUERIES], hostTNode.injectorIndex); + getLView()[RENDERER], hostContainer[QUERIES], hostTNode.injectorIndex); } else { return null; } @@ -137,7 +137,7 @@ export function createTemplateRef( let R3ViewContainerRef: { new ( lContainer: LContainer, hostTNode: TElementNode | TContainerNode | TElementContainerNode, - hostView: LViewData): ViewEngine_ViewContainerRef + hostView: LView): ViewEngine_ViewContainerRef }; /** @@ -151,13 +151,13 @@ export function injectViewContainerRef( ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_ViewContainerRef { const previousTNode = getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode; - return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, getViewData()); + return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, getLView()); } export class NodeInjector implements Injector { constructor( - private _tNode: TElementNode|TContainerNode|TElementContainerNode, - private _hostView: LViewData) {} + private _tNode: TElementNode|TContainerNode|TElementContainerNode, private _hostView: LView) { + } get(token: any, notFoundValue?: any): any { return getOrCreateInjectable( @@ -178,7 +178,7 @@ export function createContainerRef( ViewContainerRefToken: typeof ViewEngine_ViewContainerRef, ElementRefToken: typeof ViewEngine_ElementRef, hostTNode: TElementNode|TContainerNode|TElementContainerNode, - hostView: LViewData): ViewEngine_ViewContainerRef { + hostView: LView): ViewEngine_ViewContainerRef { if (!R3ViewContainerRef) { // TODO: Fix class name, should be ViewContainerRef, but there appears to be a rollup bug R3ViewContainerRef = class ViewContainerRef_ extends ViewContainerRefToken { @@ -187,7 +187,7 @@ export function createContainerRef( constructor( private _lContainer: LContainer, private _hostTNode: TElementNode|TContainerNode|TElementContainerNode, - private _hostView: LViewData) { + private _hostView: LView) { super(); } @@ -249,7 +249,7 @@ export function createContainerRef( if (viewRef.destroyed) { throw new Error('Cannot insert a destroyed View in a ViewContainer!'); } - const lView = (viewRef as ViewRef)._view !; + const lView = (viewRef as ViewRef)._lView !; const adjustedIdx = this._adjustIndex(index); insertView(lView, this._lContainer, this._hostView, adjustedIdx, this._hostTNode.index); @@ -341,7 +341,7 @@ export function createContainerRef( /** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */ export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef { - return createViewRef(getPreviousOrParentTNode(), getViewData(), null); + return createViewRef(getPreviousOrParentTNode(), getLView(), null); } /** @@ -353,7 +353,7 @@ export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef { * @returns The ChangeDetectorRef to use */ export function createViewRef( - hostTNode: TNode, hostView: LViewData, context: any): ViewEngine_ChangeDetectorRef { + hostTNode: TNode, hostView: LView, context: any): ViewEngine_ChangeDetectorRef { if (isComponent(hostTNode)) { const componentIndex = hostTNode.flags >> TNodeFlags.DirectiveStartingIndexShift; const componentView = getComponentViewByIndex(hostTNode.index, hostView); @@ -365,7 +365,7 @@ export function createViewRef( return null !; } -function getOrCreateRenderer2(view: LViewData): Renderer2 { +function getOrCreateRenderer2(view: LView): Renderer2 { const renderer = view[RENDERER]; if (isProceduralRenderer(renderer)) { return renderer as Renderer2; @@ -376,5 +376,5 @@ function getOrCreateRenderer2(view: LViewData): Renderer2 { /** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */ export function injectRenderer2(): Renderer2 { - return getOrCreateRenderer2(getViewData()); + return getOrCreateRenderer2(getLView()); } diff --git a/packages/core/src/render3/view_engine_compatibility_prebound.ts b/packages/core/src/render3/view_engine_compatibility_prebound.ts index 56fe280f16..93842fa4a7 100644 --- a/packages/core/src/render3/view_engine_compatibility_prebound.ts +++ b/packages/core/src/render3/view_engine_compatibility_prebound.ts @@ -11,7 +11,7 @@ import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref'; import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref'; import {TNode} from './interfaces/node'; -import {LViewData} from './interfaces/view'; +import {LView} from './interfaces/view'; import {createTemplateRef} from './view_engine_compatibility'; @@ -20,6 +20,6 @@ import {createTemplateRef} from './view_engine_compatibility'; * Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the * `` element. */ -export function templateRefExtractor(tNode: TNode, currentView: LViewData) { +export function templateRefExtractor(tNode: TNode, currentView: LView) { return createTemplateRef(ViewEngine_TemplateRef, ViewEngine_ElementRef, tNode, currentView); } diff --git a/packages/core/src/render3/view_ref.ts b/packages/core/src/render3/view_ref.ts index 4ef3d0f2f1..03ab0186f5 100644 --- a/packages/core/src/render3/view_ref.ts +++ b/packages/core/src/render3/view_ref.ts @@ -13,9 +13,8 @@ import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEn import {checkNoChanges, checkNoChangesInRootView, detectChanges, detectChangesInRootView, markViewDirty, storeCleanupFn, viewAttached} from './instructions'; import {TNode, TNodeType, TViewNode} from './interfaces/node'; -import {FLAGS, HOST, HOST_NODE, LViewData, LViewFlags, PARENT, RENDERER_FACTORY} from './interfaces/view'; +import {FLAGS, HOST, HOST_NODE, LView, LViewFlags, PARENT, RENDERER_FACTORY} from './interfaces/view'; import {destroyLView} from './node_manipulation'; -import {getRendererFactory} from './state'; import {getNativeByTNode} from './util'; @@ -33,42 +32,42 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int /** * @internal */ - _view: LViewData; + public _tViewNode: TViewNode|null = null; /** * @internal */ - _tViewNode: TViewNode|null = null; + public _lView: LView; get rootNodes(): any[] { - if (this._view[HOST] == null) { - const tView = this._view[HOST_NODE] as TViewNode; - return collectNativeNodes(this._view, tView, []); + if (this._lView[HOST] == null) { + const tView = this._lView[HOST_NODE] as TViewNode; + return collectNativeNodes(this._lView, tView, []); } return []; } - constructor(_view: LViewData, private _context: T|null, private _componentIndex: number) { - this._view = _view; + constructor(_lView: LView, private _context: T|null, private _componentIndex: number) { + this._lView = _lView; } get context(): T { return this._context ? this._context : this._lookUpContext(); } get destroyed(): boolean { - return (this._view[FLAGS] & LViewFlags.Destroyed) === LViewFlags.Destroyed; + return (this._lView[FLAGS] & LViewFlags.Destroyed) === LViewFlags.Destroyed; } destroy(): void { if (this._appRef) { this._appRef.detachView(this); - } else if (this._viewContainerRef && viewAttached(this._view)) { + } else if (this._viewContainerRef && viewAttached(this._lView)) { this._viewContainerRef.detach(this._viewContainerRef.indexOf(this)); this._viewContainerRef = null; } - destroyLView(this._view); + destroyLView(this._lView); } - onDestroy(callback: Function) { storeCleanupFn(this._view, callback); } + onDestroy(callback: Function) { storeCleanupFn(this._lView, callback); } /** * Marks a view and all of its ancestors dirty. @@ -104,7 +103,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * } * ``` */ - markForCheck(): void { markViewDirty(this._view); } + markForCheck(): void { markViewDirty(this._lView); } /** * Detaches the view from the change detection tree. @@ -159,7 +158,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * } * ``` */ - detach(): void { this._view[FLAGS] &= ~LViewFlags.Attached; } + detach(): void { this._lView[FLAGS] &= ~LViewFlags.Attached; } /** * Re-attaches a view to the change detection tree. @@ -217,7 +216,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * } * ``` */ - reattach(): void { this._view[FLAGS] |= LViewFlags.Attached; } + reattach(): void { this._lView[FLAGS] |= LViewFlags.Attached; } /** * Checks the view and its children. @@ -241,7 +240,7 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int * See {@link ChangeDetectorRef#detach detach} for more information. */ detectChanges(): void { - const rendererFactory = this._view[RENDERER_FACTORY]; + const rendererFactory = this._lView[RENDERER_FACTORY]; if (rendererFactory.begin) { rendererFactory.begin(); } @@ -266,13 +265,13 @@ export class ViewRef implements viewEngine_EmbeddedViewRef, viewEngine_Int attachToAppRef(appRef: ApplicationRef) { this._appRef = appRef; } private _lookUpContext(): T { - return this._context = this._view[PARENT] ![this._componentIndex] as T; + return this._context = this._lView[PARENT] ![this._componentIndex] as T; } } /** @internal */ export class RootViewRef extends ViewRef { - constructor(public _view: LViewData) { super(_view, null, -1); } + constructor(public _view: LView) { super(_view, null, -1); } detectChanges(): void { detectChangesInRootView(this._view); } @@ -281,7 +280,7 @@ export class RootViewRef extends ViewRef { get context(): T { return null !; } } -function collectNativeNodes(lView: LViewData, parentTNode: TNode, result: any[]): any[] { +function collectNativeNodes(lView: LView, parentTNode: TNode, result: any[]): any[] { let tNodeChild = parentTNode.child; while (tNodeChild) { diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index 21430bd090..df1c85fcd2 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {getCurrentSanitizer} from '../render3/state'; +import {SANITIZER} from '../render3/interfaces/view'; +import {getLView} from '../render3/state'; import {stringify} from '../render3/util'; import {BypassType, allowSanitizationBypass} from './bypass'; @@ -31,9 +32,9 @@ import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer'; * and urls have been removed. */ export function sanitizeHtml(unsafeHtml: any): string { - const s = getCurrentSanitizer(); - if (s) { - return s.sanitize(SecurityContext.HTML, unsafeHtml) || ''; + const sanitizer = getLView()[SANITIZER]; + if (sanitizer) { + return sanitizer.sanitize(SecurityContext.HTML, unsafeHtml) || ''; } if (allowSanitizationBypass(unsafeHtml, BypassType.Html)) { return unsafeHtml.toString(); @@ -55,9 +56,9 @@ export function sanitizeHtml(unsafeHtml: any): string { * dangerous javascript and urls have been removed. */ export function sanitizeStyle(unsafeStyle: any): string { - const s = getCurrentSanitizer(); - if (s) { - return s.sanitize(SecurityContext.STYLE, unsafeStyle) || ''; + const sanitizer = getLView()[SANITIZER]; + if (sanitizer) { + return sanitizer.sanitize(SecurityContext.STYLE, unsafeStyle) || ''; } if (allowSanitizationBypass(unsafeStyle, BypassType.Style)) { return unsafeStyle.toString(); @@ -80,9 +81,9 @@ export function sanitizeStyle(unsafeStyle: any): string { * all of the dangerous javascript has been removed. */ export function sanitizeUrl(unsafeUrl: any): string { - const s = getCurrentSanitizer(); - if (s) { - return s.sanitize(SecurityContext.URL, unsafeUrl) || ''; + const sanitizer = getLView()[SANITIZER]; + if (sanitizer) { + return sanitizer.sanitize(SecurityContext.URL, unsafeUrl) || ''; } if (allowSanitizationBypass(unsafeUrl, BypassType.Url)) { return unsafeUrl.toString(); @@ -100,9 +101,9 @@ export function sanitizeUrl(unsafeUrl: any): string { * only trusted `url`s have been allowed to pass. */ export function sanitizeResourceUrl(unsafeResourceUrl: any): string { - const s = getCurrentSanitizer(); - if (s) { - return s.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || ''; + const sanitizer = getLView()[SANITIZER]; + if (sanitizer) { + return sanitizer.sanitize(SecurityContext.RESOURCE_URL, unsafeResourceUrl) || ''; } if (allowSanitizationBypass(unsafeResourceUrl, BypassType.ResourceUrl)) { return unsafeResourceUrl.toString(); @@ -113,16 +114,17 @@ export function sanitizeResourceUrl(unsafeResourceUrl: any): string { /** * A `script` sanitizer which only lets trusted javascript through. * - * This passes only `script`s marked trusted by calling {@link bypassSanitizationTrustScript}. + * This passes only `script`s marked trusted by calling {@link + * bypassSanitizationTrustScript}. * * @param unsafeScript untrusted `script`, typically from the user. * @returns `url` string which is safe to bind to the `