refactor(ivy): simplify differentiation of LView, `RNode`, `LView`, `LContainer`, `StylingContext` (#28947)
For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`, `StylingContext`) in same location in `LView`. This is because we don't want to pre-allocate space for it because the storage is sparse. This file contains utilities for dealing with such data types. How do we know what is stored at a given location in `LView`. - `Array.isArray(value) === false` => `RNode` (The normal storage value) - `Array.isArray(value) === true` => than the `value[0]` represents the wrapped value. - `typeof value[TYPE] === 'object'` => `LView` - This happens when we have a component at a given location - `typeof value[TYPE] === 'number'` => `StylingContext` - This happens when we have style/class binding at a given location. - `typeof value[TYPE] === true` => `LContainer` - This happens when we have `LContainer` binding at a given location. NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient. PR Close #28947
This commit is contained in:
parent
bd65f58784
commit
3cb497c6ac
|
@ -12,9 +12,9 @@ import {assertDomNode} from '../util/assert';
|
||||||
import {EMPTY_ARRAY} from './empty';
|
import {EMPTY_ARRAY} from './empty';
|
||||||
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
|
import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
|
||||||
import {TNode, TNodeFlags} from './interfaces/node';
|
import {TNode, TNodeFlags} from './interfaces/node';
|
||||||
import {RElement} from './interfaces/renderer';
|
import {RElement, RNode} from './interfaces/renderer';
|
||||||
import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view';
|
import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view';
|
||||||
import {getComponentViewByIndex, getNativeByTNode, readElementValue, readPatchedData} from './util/view_utils';
|
import {getComponentViewByIndex, getNativeByTNode, readPatchedData, unwrapRNode} from './util/view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export function getLContext(target: any): LContext|null {
|
||||||
// are expensive. Instead, only the target data (the element, component, container, ICU
|
// are expensive. Instead, only the target data (the element, component, container, ICU
|
||||||
// expression or directive details) are filled into the context. If called multiple times
|
// expression 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.
|
// with different target values then the missing target data will be filled in.
|
||||||
const native = readElementValue(lView[nodeIndex]);
|
const native = unwrapRNode(lView[nodeIndex]);
|
||||||
const existingCtx = readPatchedData(native);
|
const existingCtx = readPatchedData(native);
|
||||||
const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ?
|
const context: LContext = (existingCtx && !Array.isArray(existingCtx)) ?
|
||||||
existingCtx :
|
existingCtx :
|
||||||
|
@ -119,7 +119,7 @@ export function getLContext(target: any): LContext|null {
|
||||||
|
|
||||||
const index = findViaNativeElement(lView, rElement);
|
const index = findViaNativeElement(lView, rElement);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
const native = readElementValue(lView[index]);
|
const native = unwrapRNode(lView[index]);
|
||||||
const context = createLContext(lView, index, native);
|
const context = createLContext(lView, index, native);
|
||||||
attachPatchData(native, context);
|
attachPatchData(native, context);
|
||||||
mpValue = context;
|
mpValue = context;
|
||||||
|
@ -134,7 +134,7 @@ export function getLContext(target: any): LContext|null {
|
||||||
/**
|
/**
|
||||||
* Creates an empty instance of a `LContext` context
|
* Creates an empty instance of a `LContext` context
|
||||||
*/
|
*/
|
||||||
function createLContext(lView: LView, nodeIndex: number, native: RElement): LContext {
|
function createLContext(lView: LView, nodeIndex: number, native: RNode): LContext {
|
||||||
return {
|
return {
|
||||||
lView,
|
lView,
|
||||||
nodeIndex,
|
nodeIndex,
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {LQueries} from './interfaces/query';
|
||||||
import {RComment, RElement} from './interfaces/renderer';
|
import {RComment, RElement} from './interfaces/renderer';
|
||||||
import {StylingContext} from './interfaces/styling';
|
import {StylingContext} from './interfaces/styling';
|
||||||
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, TView, T_HOST} from './interfaces/view';
|
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TVIEW, TView, T_HOST} from './interfaces/view';
|
||||||
import {readElementValue} from './util/view_utils';
|
import {unwrapRNode} from './util/view_utils';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file contains conditionally attached classes which provide human readable (debug) level
|
* This file contains conditionally attached classes which provide human readable (debug) level
|
||||||
|
@ -77,7 +77,7 @@ export function toDebug(obj: any): any {
|
||||||
* (will not serialize child elements).
|
* (will not serialize child elements).
|
||||||
*/
|
*/
|
||||||
function toHtml(value: any, includeChildren: boolean = false): string|null {
|
function toHtml(value: any, includeChildren: boolean = false): string|null {
|
||||||
const node: HTMLElement|null = readElementValue(value) as any;
|
const node: HTMLElement|null = unwrapRNode(value) as any;
|
||||||
if (node) {
|
if (node) {
|
||||||
const isTextNode = node.nodeType === Node.TEXT_NODE;
|
const isTextNode = node.nodeType === Node.TEXT_NODE;
|
||||||
const outerHTML = (isTextNode ? node.textContent : node.outerHTML) || '';
|
const outerHTML = (isTextNode ? node.textContent : node.outerHTML) || '';
|
||||||
|
@ -182,7 +182,7 @@ export function toDebugNodes(tNode: TNode | null, lView: LView): DebugNode[]|nul
|
||||||
let tNodeCursor: TNode|null = tNode;
|
let tNodeCursor: TNode|null = tNode;
|
||||||
while (tNodeCursor) {
|
while (tNodeCursor) {
|
||||||
const rawValue = lView[tNode.index];
|
const rawValue = lView[tNode.index];
|
||||||
const native = readElementValue(rawValue);
|
const native = unwrapRNode(rawValue);
|
||||||
const componentLViewDebug = toDebug(readLViewValue(rawValue));
|
const componentLViewDebug = toDebug(readLViewValue(rawValue));
|
||||||
debugNodes.push({
|
debugNodes.push({
|
||||||
html: toHtml(native),
|
html: toHtml(native),
|
||||||
|
|
|
@ -47,7 +47,7 @@ import {ANIMATION_PROP_PREFIX, allocateDirectiveIntoContext, createEmptyStylingC
|
||||||
import {NO_CHANGE} from './tokens';
|
import {NO_CHANGE} from './tokens';
|
||||||
import {INTERPOLATION_DELIMITER, renderStringify} from './util/misc_utils';
|
import {INTERPOLATION_DELIMITER, renderStringify} from './util/misc_utils';
|
||||||
import {findComponentView, getLViewParent, getRootContext, getRootView} from './util/view_traversal_utils';
|
import {findComponentView, getLViewParent, getRootContext, getRootView} from './util/view_traversal_utils';
|
||||||
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readElementValue, readPatchedLView} from './util/view_utils';
|
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, loadInternal, readPatchedLView, unwrapRNode} from './util/view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
||||||
if (instruction !== null) {
|
if (instruction !== null) {
|
||||||
viewData[BINDING_INDEX] = bindingRootIndex;
|
viewData[BINDING_INDEX] = bindingRootIndex;
|
||||||
instruction(
|
instruction(
|
||||||
RenderFlags.Update, readElementValue(viewData[currentDirectiveIndex]),
|
RenderFlags.Update, unwrapRNode(viewData[currentDirectiveIndex]),
|
||||||
currentElementIndex);
|
currentElementIndex);
|
||||||
}
|
}
|
||||||
currentDirectiveIndex++;
|
currentDirectiveIndex++;
|
||||||
|
@ -1018,7 +1018,7 @@ function listenerInternal(
|
||||||
}
|
}
|
||||||
|
|
||||||
const idxOrTargetGetter = eventTargetResolver ?
|
const idxOrTargetGetter = eventTargetResolver ?
|
||||||
(_lView: LView) => eventTargetResolver(readElementValue(_lView[tNode.index])).target :
|
(_lView: LView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])).target :
|
||||||
tNode.index;
|
tNode.index;
|
||||||
tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCaptureOrSubIdx);
|
tCleanup && tCleanup.push(eventName, idxOrTargetGetter, lCleanupIndex, useCaptureOrSubIdx);
|
||||||
}
|
}
|
||||||
|
@ -1147,7 +1147,7 @@ export function elementAttribute(
|
||||||
ngDevMode && validateAgainstEventAttributes(name);
|
ngDevMode && validateAgainstEventAttributes(name);
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const renderer = lView[RENDERER];
|
const renderer = lView[RENDERER];
|
||||||
const element = getNativeByIndex(index, lView);
|
const element = getNativeByIndex(index, lView) as RElement;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
ngDevMode && ngDevMode.rendererRemoveAttribute++;
|
ngDevMode && ngDevMode.rendererRemoveAttribute++;
|
||||||
isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
|
isProceduralRenderer(renderer) ? renderer.removeAttribute(element, name, namespace) :
|
||||||
|
@ -2217,11 +2217,12 @@ export function createLContainer(
|
||||||
ngDevMode && assertLView(currentView);
|
ngDevMode && assertLView(currentView);
|
||||||
const lContainer: LContainer = [
|
const lContainer: LContainer = [
|
||||||
hostNative, // host native
|
hostNative, // host native
|
||||||
|
true, // Boolean `true` in this position signifies that this is an `LContainer`
|
||||||
isForViewContainerRef ? -1 : 0, // active index
|
isForViewContainerRef ? -1 : 0, // active index
|
||||||
[], // views
|
|
||||||
currentView, // parent
|
currentView, // parent
|
||||||
null, // next
|
null, // next
|
||||||
null, // queries
|
null, // queries
|
||||||
|
[], // views
|
||||||
native, // native
|
native, // native
|
||||||
];
|
];
|
||||||
ngDevMode && attachLContainerDebug(lContainer);
|
ngDevMode && attachLContainerDebug(lContainer);
|
||||||
|
|
|
@ -11,25 +11,22 @@ import {RComment, RElement} from './renderer';
|
||||||
import {StylingContext} from './styling';
|
import {StylingContext} from './styling';
|
||||||
import {HOST, LView, NEXT, PARENT, QUERIES} from './view';
|
import {HOST, LView, NEXT, PARENT, QUERIES} from './view';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special location which allows easy identification of type. If we have an array which was
|
||||||
|
* retrieved from the `LView` and that array has `true` at `TYPE` location, we know it is
|
||||||
|
* `LContainer`.
|
||||||
|
*/
|
||||||
|
export const TYPE = 1;
|
||||||
/**
|
/**
|
||||||
* Below are constants for LContainer indices to help us look up LContainer members
|
* Below are constants for LContainer indices to help us look up LContainer members
|
||||||
* without having to remember the specific indices.
|
* without having to remember the specific indices.
|
||||||
* Uglify will inline these when minifying so there shouldn't be a cost.
|
* Uglify will inline these when minifying so there shouldn't be a cost.
|
||||||
*/
|
*/
|
||||||
export const ACTIVE_INDEX = 1;
|
export const ACTIVE_INDEX = 2;
|
||||||
export const VIEWS = 2;
|
// PARENT, NEXT, and QUERIES are indices 3, 4, and 5.
|
||||||
// PARENT, NEXT, QUERIES, and HOST are indices 2, 3, 4, and 5.
|
|
||||||
// As we already have these constants in LView, 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 VIEWS = 6;
|
||||||
// Because interfaces in TS/JS cannot be instanceof-checked this means that we
|
export const NATIVE = 7;
|
||||||
// need to rely on predictable characteristics of data-structures to check if they
|
|
||||||
// are what we expect for them to be. The `LContainer` interface code below has a
|
|
||||||
// fixed length and the constant value below references that. Using the length value
|
|
||||||
// below we can predictably gaurantee that we are dealing with an `LContainer` array.
|
|
||||||
// This value MUST be kept up to date with the length of the `LContainer` array
|
|
||||||
// interface below so that runtime type checking can work.
|
|
||||||
export const LCONTAINER_LENGTH = 7;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state associated with a container.
|
* The state associated with a container.
|
||||||
|
@ -51,6 +48,12 @@ export interface LContainer extends Array<any> {
|
||||||
*/
|
*/
|
||||||
readonly[HOST]: RElement|RComment|StylingContext|LView;
|
readonly[HOST]: RElement|RComment|StylingContext|LView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a type field which allows us to differentiate `LContainer` from `StylingContext` in an
|
||||||
|
* efficient way. The value is always set to `true`
|
||||||
|
*/
|
||||||
|
[TYPE]: true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The next active index in the views array to read or write to. This helps us
|
* The next active index in the views array to read or write to. This helps us
|
||||||
* keep track of where we are in the views array.
|
* keep track of where we are in the views array.
|
||||||
|
@ -60,15 +63,6 @@ export interface LContainer extends Array<any> {
|
||||||
*/
|
*/
|
||||||
[ACTIVE_INDEX]: number;
|
[ACTIVE_INDEX]: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of the container's currently active child views. Views will be inserted
|
|
||||||
* here as they are added and spliced from here when they are removed. We need
|
|
||||||
* to keep a record of current views so we know which views are already in the DOM
|
|
||||||
* (and don't need to be re-added) and so we can remove views from the DOM when they
|
|
||||||
* are no longer required.
|
|
||||||
*/
|
|
||||||
[VIEWS]: LView[];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to the parent view is necessary so we can propagate back
|
* Access to the parent view is necessary so we can propagate back
|
||||||
* up from inside a container to parent[NEXT].
|
* up from inside a container to parent[NEXT].
|
||||||
|
@ -85,10 +79,21 @@ export interface LContainer extends Array<any> {
|
||||||
* Queries active for this container - all the views inserted to / removed from
|
* Queries active for this container - all the views inserted to / removed from
|
||||||
* this container are reported to queries referenced here.
|
* this container are reported to queries referenced here.
|
||||||
*/
|
*/
|
||||||
[QUERIES]: LQueries|null;
|
[QUERIES]: LQueries|null; // TODO(misko): This is abuse of `LContainer` since we are storing
|
||||||
|
// `[QUERIES]` in it which are not needed for `LContainer` (only needed for Template)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the container's currently active child views. Views will be inserted
|
||||||
|
* here as they are added and spliced from here when they are removed. We need
|
||||||
|
* to keep a record of current views so we know which views are already in the DOM
|
||||||
|
* (and don't need to be re-added) and so we can remove views from the DOM when they
|
||||||
|
* are no longer required.
|
||||||
|
*/
|
||||||
|
[VIEWS]: LView[];
|
||||||
|
|
||||||
/** The comment element that serves as an anchor for this LContainer. */
|
/** The comment element that serves as an anchor for this LContainer. */
|
||||||
readonly[NATIVE]: RComment;
|
readonly[NATIVE]:
|
||||||
|
RComment; // TODO(misko): remove as this value can be gotten by unwrapping `[HOST]`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import {RElement} from './renderer';
|
import {RNode} from './renderer';
|
||||||
import {LView} from './view';
|
import {LView} from './view';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +39,7 @@ export interface LContext {
|
||||||
/**
|
/**
|
||||||
* The instance of the DOM node that is attached to the lNode.
|
* The instance of the DOM node that is attached to the lNode.
|
||||||
*/
|
*/
|
||||||
native: RElement;
|
native: RNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The instance of the Component node.
|
* The instance of the Component node.
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
*/
|
*/
|
||||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||||
import {RElement} from '../interfaces/renderer';
|
import {RElement} from '../interfaces/renderer';
|
||||||
|
import {LContainer} from './container';
|
||||||
import {PlayerContext} from './player';
|
import {PlayerContext} from './player';
|
||||||
|
import {LView} from './view';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The styling context acts as a styling manifest (shaped as an array) for determining which
|
* The styling context acts as a styling manifest (shaped as an array) for determining which
|
||||||
|
@ -263,7 +266,7 @@ export interface StylingContext extends
|
||||||
/**
|
/**
|
||||||
* Location of element that is used as a target for this context.
|
* Location of element that is used as a target for this context.
|
||||||
*/
|
*/
|
||||||
[StylingIndex.ElementPosition]: RElement|null;
|
[StylingIndex.ElementPosition]: LContainer|LView|RElement|null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A numeric value representing the configuration status (whether the context is dirty or not)
|
* A numeric value representing the configuration status (whether the context is dirty or not)
|
||||||
|
|
|
@ -72,6 +72,9 @@ export interface LView extends Array<any> {
|
||||||
* The host node for this LView 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.
|
* If this is an embedded view, HOST will be null.
|
||||||
|
*
|
||||||
|
* If the component uses host bindings for styling that the `RElement` will be wrapped with
|
||||||
|
* `StylingContext`.
|
||||||
*/
|
*/
|
||||||
[HOST]: RElement|StylingContext|null;
|
[HOST]: RElement|StylingContext|null;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {CHILD_HEAD, CLEANUP, FLAGS, HEADER_OFFSET, HookData, LView, LViewFlags,
|
||||||
import {assertNodeType} from './node_assert';
|
import {assertNodeType} from './node_assert';
|
||||||
import {renderStringify} from './util/misc_utils';
|
import {renderStringify} from './util/misc_utils';
|
||||||
import {findComponentView, getLViewParent} from './util/view_traversal_utils';
|
import {findComponentView, getLViewParent} from './util/view_traversal_utils';
|
||||||
import {getNativeByTNode, isComponent, isLContainer, isLView, isRootView, readElementValue} from './util/view_utils';
|
import {getNativeByTNode, isComponent, isLContainer, isLView, isRootView, unwrapRNode} from './util/view_utils';
|
||||||
|
|
||||||
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4 + unused5;
|
||||||
|
|
||||||
|
@ -200,8 +200,8 @@ function walkTNodeTree(
|
||||||
* being passed as an argument.
|
* being passed as an argument.
|
||||||
*/
|
*/
|
||||||
function executeNodeAction(
|
function executeNodeAction(
|
||||||
action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement | null,
|
action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement | null, node: RNode,
|
||||||
node: RComment | RElement | RText, tNode: TNode, beforeNode?: RNode | null) {
|
tNode: TNode, beforeNode?: RNode | null) {
|
||||||
if (action === WalkTNodeTreeAction.Insert) {
|
if (action === WalkTNodeTreeAction.Insert) {
|
||||||
nativeInsertBefore(renderer, parent !, node, beforeNode || null);
|
nativeInsertBefore(renderer, parent !, node, beforeNode || null);
|
||||||
} else if (action === WalkTNodeTreeAction.Detach) {
|
} else if (action === WalkTNodeTreeAction.Detach) {
|
||||||
|
@ -454,7 +454,7 @@ function removeListeners(lView: LView): void {
|
||||||
const idxOrTargetGetter = tCleanup[i + 1];
|
const idxOrTargetGetter = tCleanup[i + 1];
|
||||||
const target = typeof idxOrTargetGetter === 'function' ?
|
const target = typeof idxOrTargetGetter === 'function' ?
|
||||||
idxOrTargetGetter(lView) :
|
idxOrTargetGetter(lView) :
|
||||||
readElementValue(lView[idxOrTargetGetter]);
|
unwrapRNode(lView[idxOrTargetGetter]);
|
||||||
const listener = lCleanup[tCleanup[i + 2]];
|
const listener = lCleanup[tCleanup[i + 2]];
|
||||||
const useCaptureOrSubIdx = tCleanup[i + 3];
|
const useCaptureOrSubIdx = tCleanup[i + 3];
|
||||||
if (typeof useCaptureOrSubIdx === 'boolean') {
|
if (typeof useCaptureOrSubIdx === 'boolean') {
|
||||||
|
|
|
@ -9,25 +9,25 @@ import '../../util/ng_dev_mode';
|
||||||
|
|
||||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||||
import {getLContext} from '../context_discovery';
|
import {getLContext} from '../context_discovery';
|
||||||
import {LCONTAINER_LENGTH, LContainer} from '../interfaces/container';
|
import {LContainer} from '../interfaces/container';
|
||||||
import {LContext} from '../interfaces/context';
|
import {LContext} from '../interfaces/context';
|
||||||
import {AttributeMarker, TAttributes, TNode, TNodeFlags} from '../interfaces/node';
|
import {AttributeMarker, TAttributes, TNode, TNodeFlags} from '../interfaces/node';
|
||||||
import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/player';
|
import {PlayState, Player, PlayerContext, PlayerIndex} from '../interfaces/player';
|
||||||
import {RElement} from '../interfaces/renderer';
|
import {RElement} from '../interfaces/renderer';
|
||||||
import {InitialStylingValues, InitialStylingValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
|
import {InitialStylingValues, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
|
||||||
import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view';
|
import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view';
|
||||||
import {getTNode} from '../util/view_utils';
|
import {getTNode, isStylingContext} from '../util/view_utils';
|
||||||
|
|
||||||
import {CorePlayerHandler} from './core_player_handler';
|
import {CorePlayerHandler} from './core_player_handler';
|
||||||
|
|
||||||
export const ANIMATION_PROP_PREFIX = '@';
|
export const ANIMATION_PROP_PREFIX = '@';
|
||||||
|
|
||||||
export function createEmptyStylingContext(
|
export function createEmptyStylingContext(
|
||||||
element?: RElement | null, sanitizer?: StyleSanitizeFn | null,
|
wrappedElement?: LContainer | LView | RElement | null, sanitizer?: StyleSanitizeFn | null,
|
||||||
initialStyles?: InitialStylingValues | null,
|
initialStyles?: InitialStylingValues | null,
|
||||||
initialClasses?: InitialStylingValues | null): StylingContext {
|
initialClasses?: InitialStylingValues | null): StylingContext {
|
||||||
const context: StylingContext = [
|
const context: StylingContext = [
|
||||||
element || null, // Element
|
wrappedElement || null, // Element
|
||||||
0, // MasterFlags
|
0, // MasterFlags
|
||||||
[] as any, // DirectiveRefs (this gets filled below)
|
[] as any, // DirectiveRefs (this gets filled below)
|
||||||
initialStyles || [null, null], // InitialStyles
|
initialStyles || [null, null], // InitialStyles
|
||||||
|
@ -95,7 +95,7 @@ export function getStylingContext(index: number, viewData: LView): StylingContex
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStylingContext(wrapper)) {
|
if (isStylingContext(wrapper)) {
|
||||||
return wrapper as StylingContext;
|
return wrapper;
|
||||||
} else {
|
} else {
|
||||||
// This is an LView or an LContainer
|
// This is an LView or an LContainer
|
||||||
const stylingTemplate = getTNode(index - HEADER_OFFSET, viewData).stylingTemplate;
|
const stylingTemplate = getTNode(index - HEADER_OFFSET, viewData).stylingTemplate;
|
||||||
|
@ -110,15 +110,6 @@ export function getStylingContext(index: number, viewData: LView): StylingContex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isStylingContext(value: any): boolean {
|
|
||||||
// Not an LView or an LContainer
|
|
||||||
if (Array.isArray(value) && value.length >= StylingIndex.SingleStylesStartPosition) {
|
|
||||||
return typeof value[StylingIndex.MasterFlagPosition] === 'number' &&
|
|
||||||
value[StylingIndex.InitialClassValuesPosition]
|
|
||||||
[InitialStylingValuesIndex.DefaultNullValuePosition] === null;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAnimationProp(name: string): boolean {
|
export function isAnimationProp(name: string): boolean {
|
||||||
return name[0] === ANIMATION_PROP_PREFIX;
|
return name[0] === ANIMATION_PROP_PREFIX;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node';
|
||||||
import {CLEANUP, CONTEXT, FLAGS, HOST, LView, LViewFlags, TVIEW} from '../interfaces/view';
|
import {CLEANUP, CONTEXT, FLAGS, HOST, LView, LViewFlags, TVIEW} from '../interfaces/view';
|
||||||
import {renderStringify} from './misc_utils';
|
import {renderStringify} from './misc_utils';
|
||||||
import {getLViewParent, getRootContext} from './view_traversal_utils';
|
import {getLViewParent, getRootContext} from './view_traversal_utils';
|
||||||
import {readElementValue} from './view_utils';
|
import {unwrapRNode} from './view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ export function getListeners(element: Element): Listener[] {
|
||||||
const secondParam = tCleanup[i++];
|
const secondParam = tCleanup[i++];
|
||||||
if (typeof firstParam === 'string') {
|
if (typeof firstParam === 'string') {
|
||||||
const name: string = firstParam;
|
const name: string = firstParam;
|
||||||
const listenerElement = readElementValue(lView[secondParam]) as any as Element;
|
const listenerElement = unwrapRNode(lView[secondParam]) as any as Element;
|
||||||
const callback: (value: any) => any = lCleanup[tCleanup[i++]];
|
const callback: (value: any) => any = lCleanup[tCleanup[i++]];
|
||||||
const useCaptureOrIndx = tCleanup[i++];
|
const useCaptureOrIndx = tCleanup[i++];
|
||||||
// if useCaptureOrIndx is boolean then report it as is.
|
// if useCaptureOrIndx is boolean then report it as is.
|
||||||
|
|
|
@ -7,43 +7,128 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from '../../util/assert';
|
import {assertDataInRange, assertDefined, assertGreaterThan, assertLessThan} from '../../util/assert';
|
||||||
import {LCONTAINER_LENGTH, LContainer} from '../interfaces/container';
|
import {LContainer, TYPE} from '../interfaces/container';
|
||||||
import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context';
|
import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context';
|
||||||
import {ComponentDef, DirectiveDef} from '../interfaces/definition';
|
import {ComponentDef, DirectiveDef} from '../interfaces/definition';
|
||||||
import {TNode, TNodeFlags} from '../interfaces/node';
|
import {TNode, TNodeFlags} from '../interfaces/node';
|
||||||
import {RComment, RElement, RText} from '../interfaces/renderer';
|
import {RNode} from '../interfaces/renderer';
|
||||||
|
import {StylingContext} from '../interfaces/styling';
|
||||||
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TData, TVIEW} from '../interfaces/view';
|
import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TData, TVIEW} from '../interfaces/view';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the value of a slot in `LView` and returns the element node.
|
* For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`,
|
||||||
|
* `StylingContext`) in same location in `LView`. This is because we don't want to pre-allocate
|
||||||
|
* space for it because the storage is sparse. This file contains utilities for dealing with such
|
||||||
|
* data types.
|
||||||
*
|
*
|
||||||
* Normally, element nodes are stored flat, but if the node has styles/classes on it,
|
* How do we know what is stored at a given location in `LView`.
|
||||||
* it might be wrapped in a styling context. Or if that node has a directive that injects
|
* - `Array.isArray(value) === false` => `RNode` (The normal storage value)
|
||||||
* ViewContainerRef, it may be wrapped in an LContainer. Or if that node is a component,
|
* - `Array.isArray(value) === true` => then the `value[0]` represents the wrapped value.
|
||||||
* it will be wrapped in LView. It could even have all three, so we keep looping
|
* - `typeof value[TYPE] === 'object'` => `LView`
|
||||||
* until we find something that isn't an array.
|
* - This happens when we have a component at a given location
|
||||||
|
* - `typeof value[TYPE] === 'number'` => `StylingContext`
|
||||||
|
* - This happens when we have style/class binding at a given location.
|
||||||
|
* - `typeof value[TYPE] === true` => `LContainer`
|
||||||
|
* - This happens when we have `LContainer` binding at a given location.
|
||||||
*
|
*
|
||||||
* @param value The initial value in `LView`
|
*
|
||||||
|
* NOTE: it is assumed that `Array.isArray` and `typeof` operations are very efficient.
|
||||||
*/
|
*/
|
||||||
export function readElementValue(value: any): RElement {
|
|
||||||
|
/**
|
||||||
|
* Returns `RNode`.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function unwrapRNode(value: RNode | LView | LContainer | StylingContext): RNode {
|
||||||
while (Array.isArray(value)) {
|
while (Array.isArray(value)) {
|
||||||
value = value[HOST] as any;
|
value = value[HOST] as any;
|
||||||
}
|
}
|
||||||
return value;
|
return value as RNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `LView` or `null` if not found.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function unwrapLView(value: RNode | LView | LContainer | StylingContext): LView|null {
|
||||||
|
while (Array.isArray(value)) {
|
||||||
|
// This check is same as `isLView()` but we don't call at as we don't want to call
|
||||||
|
// `Array.isArray()` twice and give JITer more work for inlining.
|
||||||
|
if (typeof value[TYPE] === 'object') return value as LView;
|
||||||
|
value = value[HOST] as any;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `LContainer` or `null` if not found.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function unwrapLContainer(value: RNode | LView | LContainer | StylingContext): LContainer|
|
||||||
|
null {
|
||||||
|
while (Array.isArray(value)) {
|
||||||
|
// This check is same as `isLContainer()` but we don't call at as we don't want to call
|
||||||
|
// `Array.isArray()` twice and give JITer more work for inlining.
|
||||||
|
if (value[TYPE] === true) return value as LContainer;
|
||||||
|
value = value[HOST] as any;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `StylingContext` or `null` if not found.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function unwrapStylingContext(value: RNode | LView | LContainer | StylingContext):
|
||||||
|
StylingContext|null {
|
||||||
|
while (Array.isArray(value)) {
|
||||||
|
// This check is same as `isStylingContext()` but we don't call at as we don't want to call
|
||||||
|
// `Array.isArray()` twice and give JITer more work for inlining.
|
||||||
|
if (typeof value[TYPE] === 'number') return value as StylingContext;
|
||||||
|
value = value[HOST] as any;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if `value` is `LView`.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function isLView(value: RNode | LView | LContainer | StylingContext | {} | null):
|
||||||
|
value is LView {
|
||||||
|
return Array.isArray(value) && typeof value[TYPE] === 'object';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if `value` is `LContainer`.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function isLContainer(value: RNode | LView | LContainer | StylingContext | {} | null):
|
||||||
|
value is LContainer {
|
||||||
|
return Array.isArray(value) && value[TYPE] === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if `value` is `StylingContext`.
|
||||||
|
* @param value wrapped value of `RNode`, `LView`, `LContainer`, `StylingContext`
|
||||||
|
*/
|
||||||
|
export function isStylingContext(value: RNode | LView | LContainer | StylingContext | {} | null):
|
||||||
|
value is StylingContext {
|
||||||
|
return Array.isArray(value) && typeof value[TYPE] === 'number';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves an element value from the provided `viewData`, by unwrapping
|
* Retrieves an element value from the provided `viewData`, by unwrapping
|
||||||
* from any containers, component views, or style contexts.
|
* from any containers, component views, or style contexts.
|
||||||
*/
|
*/
|
||||||
export function getNativeByIndex(index: number, lView: LView): RElement {
|
export function getNativeByIndex(index: number, lView: LView): RNode {
|
||||||
return readElementValue(lView[index + HEADER_OFFSET]);
|
return unwrapRNode(lView[index + HEADER_OFFSET]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNativeByTNode(tNode: TNode, hostView: LView): RElement|RText|RComment {
|
export function getNativeByTNode(tNode: TNode, hostView: LView): RNode {
|
||||||
return readElementValue(hostView[tNode.index]);
|
return unwrapRNode(hostView[tNode.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTNode(index: number, view: LView): TNode {
|
export function getTNode(index: number, view: LView): TNode {
|
||||||
|
@ -52,14 +137,6 @@ export function getTNode(index: number, view: LView): TNode {
|
||||||
return view[TVIEW].data[index + HEADER_OFFSET] as TNode;
|
return view[TVIEW].data[index + HEADER_OFFSET] as TNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the value is an {@link LView}
|
|
||||||
* @param value the value to check
|
|
||||||
*/
|
|
||||||
export function isLView(value: any): value is LView {
|
|
||||||
return Array.isArray(value) && value.length >= HEADER_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves a value from any `LView` or `TData`. */
|
/** Retrieves a value from any `LView` or `TData`. */
|
||||||
export function loadInternal<T>(view: LView | TData, index: number): T {
|
export function loadInternal<T>(view: LView | TData, index: number): T {
|
||||||
ngDevMode && assertDataInRange(view, index + HEADER_OFFSET);
|
ngDevMode && assertDataInRange(view, index + HEADER_OFFSET);
|
||||||
|
@ -85,11 +162,6 @@ export function isComponentDef<T>(def: DirectiveDef<T>): def is ComponentDef<T>
|
||||||
return (def as ComponentDef<T>).template !== null;
|
return (def as ComponentDef<T>).template !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLContainer(value: any): value is LContainer {
|
|
||||||
// Styling contexts are also arrays, but their first index contains an element node
|
|
||||||
return Array.isArray(value) && value.length === LCONTAINER_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isRootView(target: LView): boolean {
|
export function isRootView(target: LView): boolean {
|
||||||
return (target[FLAGS] & LViewFlags.IsRoot) !== 0;
|
return (target[FLAGS] & LViewFlags.IsRoot) !== 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ export function createElementRef(
|
||||||
// TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug
|
// TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug
|
||||||
R3ElementRef = class ElementRef_ extends ElementRefToken {};
|
R3ElementRef = class ElementRef_ extends ElementRefToken {};
|
||||||
}
|
}
|
||||||
return new R3ElementRef(getNativeByTNode(tNode, view));
|
return new R3ElementRef(getNativeByTNode(tNode, view) as RElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
let R3TemplateRef: {
|
let R3TemplateRef: {
|
||||||
|
|
|
@ -59,9 +59,6 @@
|
||||||
{
|
{
|
||||||
"name": "INJECTOR_BLOOM_PARENT_SIZE"
|
"name": "INJECTOR_BLOOM_PARENT_SIZE"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "LCONTAINER_LENGTH"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MONKEY_PATCH_KEY_NAME"
|
"name": "MONKEY_PATCH_KEY_NAME"
|
||||||
},
|
},
|
||||||
|
@ -128,6 +125,9 @@
|
||||||
{
|
{
|
||||||
"name": "TVIEW"
|
"name": "TVIEW"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TYPE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "T_HOST"
|
"name": "T_HOST"
|
||||||
},
|
},
|
||||||
|
@ -536,9 +536,6 @@
|
||||||
{
|
{
|
||||||
"name": "readClassValueFromTNode"
|
"name": "readClassValueFromTNode"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "readElementValue"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "readPatchedData"
|
"name": "readPatchedData"
|
||||||
},
|
},
|
||||||
|
@ -653,6 +650,9 @@
|
||||||
{
|
{
|
||||||
"name": "tickRootContext"
|
"name": "tickRootContext"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "unwrapRNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "viewAttached"
|
"name": "viewAttached"
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,6 @@
|
||||||
{
|
{
|
||||||
"name": "INJECTOR_BLOOM_PARENT_SIZE"
|
"name": "INJECTOR_BLOOM_PARENT_SIZE"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "LCONTAINER_LENGTH"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MONKEY_PATCH_KEY_NAME"
|
"name": "MONKEY_PATCH_KEY_NAME"
|
||||||
},
|
},
|
||||||
|
@ -107,6 +104,9 @@
|
||||||
{
|
{
|
||||||
"name": "TVIEW"
|
"name": "TVIEW"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TYPE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "T_HOST"
|
"name": "T_HOST"
|
||||||
},
|
},
|
||||||
|
@ -383,9 +383,6 @@
|
||||||
{
|
{
|
||||||
"name": "queueComponentIndexForCheck"
|
"name": "queueComponentIndexForCheck"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "readElementValue"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "readPatchedData"
|
"name": "readPatchedData"
|
||||||
},
|
},
|
||||||
|
@ -455,6 +452,9 @@
|
||||||
{
|
{
|
||||||
"name": "tickRootContext"
|
"name": "tickRootContext"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "unwrapRNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "viewAttached"
|
"name": "viewAttached"
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,9 +104,6 @@
|
||||||
{
|
{
|
||||||
"name": "IterableDiffers"
|
"name": "IterableDiffers"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "LCONTAINER_LENGTH"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MONKEY_PATCH_KEY_NAME"
|
"name": "MONKEY_PATCH_KEY_NAME"
|
||||||
},
|
},
|
||||||
|
@ -218,6 +215,9 @@
|
||||||
{
|
{
|
||||||
"name": "TVIEW"
|
"name": "TVIEW"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "TYPE"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "T_HOST"
|
"name": "T_HOST"
|
||||||
},
|
},
|
||||||
|
@ -1085,9 +1085,6 @@
|
||||||
{
|
{
|
||||||
"name": "readClassValueFromTNode"
|
"name": "readClassValueFromTNode"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "readElementValue"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "readPatchedData"
|
"name": "readPatchedData"
|
||||||
},
|
},
|
||||||
|
@ -1283,6 +1280,9 @@
|
||||||
{
|
{
|
||||||
"name": "trackByIdentity"
|
"name": "trackByIdentity"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "unwrapRNode"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "updateClassProp"
|
"name": "updateClassProp"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1532,7 +1532,7 @@ describe('di', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
|
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
|
||||||
elementEnd();
|
elementEnd();
|
||||||
div = getNativeByIndex(0, getLView());
|
div = getNativeByIndex(0, getLView()) as RElement;
|
||||||
}
|
}
|
||||||
}, 1, 0, [Directive, DirectiveSameInstance]);
|
}, 1, 0, [Directive, DirectiveSameInstance]);
|
||||||
|
|
||||||
|
|
|
@ -2066,7 +2066,7 @@ describe('ViewContainerRef', () => {
|
||||||
element(0, 'div', ['bar', ''], ['foo', '']);
|
element(0, 'div', ['bar', ''], ['foo', '']);
|
||||||
}
|
}
|
||||||
// testing only
|
// testing only
|
||||||
fooEl = getNativeByIndex(0, getLView());
|
fooEl = getNativeByIndex(0, getLView()) as RElement;
|
||||||
},
|
},
|
||||||
viewQuery: function(rf: RenderFlags, ctx: any) {
|
viewQuery: function(rf: RenderFlags, ctx: any) {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* @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 {createLContainer, createLView, createTView} from '@angular/core/src/render3/instructions';
|
||||||
|
import {createEmptyStylingContext} from '@angular/core/src/render3/styling/util';
|
||||||
|
import {isLContainer, isLView, isStylingContext, unwrapLContainer, unwrapLView, unwrapRNode, unwrapStylingContext} from '@angular/core/src/render3/util/view_utils';
|
||||||
|
|
||||||
|
describe('view_utils', () => {
|
||||||
|
it('should verify unwrap methods', () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const tView = createTView(0, null, 0, 0, null, null, null, null);
|
||||||
|
const lView = createLView(null, tView, {}, 0, div, null, {} as any, {} as any, null, null);
|
||||||
|
const lContainer = createLContainer(lView, lView, div, true);
|
||||||
|
const styleContext = createEmptyStylingContext(lContainer, null, null, null);
|
||||||
|
|
||||||
|
expect(unwrapRNode(styleContext)).toBe(div);
|
||||||
|
expect(unwrapStylingContext(styleContext)).toBe(styleContext);
|
||||||
|
expect(unwrapLContainer(styleContext)).toBe(lContainer);
|
||||||
|
expect(unwrapLView(styleContext)).toBe(lView);
|
||||||
|
|
||||||
|
expect(isLView(lView)).toBe(true);
|
||||||
|
expect(isLView(lContainer)).toBe(false);
|
||||||
|
expect(isLView(styleContext)).toBe(false);
|
||||||
|
|
||||||
|
expect(isLContainer(lView)).toBe(false);
|
||||||
|
expect(isLContainer(lContainer)).toBe(true);
|
||||||
|
expect(isLContainer(styleContext)).toBe(false);
|
||||||
|
|
||||||
|
expect(isStylingContext(lView)).toBe(false);
|
||||||
|
expect(isStylingContext(lContainer)).toBe(false);
|
||||||
|
expect(isStylingContext(styleContext)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -16,7 +16,7 @@ import {getUrlSanitizer, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sani
|
||||||
import {SecurityContext} from '../../src/sanitization/security';
|
import {SecurityContext} from '../../src/sanitization/security';
|
||||||
|
|
||||||
function fakeLView(): LView {
|
function fakeLView(): LView {
|
||||||
return Array.from({length: HEADER_OFFSET}) as LView;
|
return [null, {}] as LView;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('sanitization', () => {
|
describe('sanitization', () => {
|
||||||
|
|
Loading…
Reference in New Issue