refactor(core): Consistent use of `HEADER_OFFSET` (in `ɵɵ*` instructions only) (#39233)
IMPORTANT: `HEADER_OFFSET` should only be refereed to the in the `ɵɵ*` instructions to translate instruction index into `LView` index. All other indexes should be in the `LView` index space and there should be no need to refer to `HEADER_OFFSET` anywhere else. PR Close #39233
This commit is contained in:
parent
bc5005e35b
commit
54303688fa
|
@ -21,7 +21,7 @@
|
|||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime-es2015": 1485,
|
||||
"main-es2015": 147242,
|
||||
"main-es2015": 146698,
|
||||
"polyfills-es2015": 36571
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import {Type} from '../core';
|
|||
import {Injector} from '../di/injector';
|
||||
import {Sanitizer} from '../sanitization/sanitizer';
|
||||
import {assertDefined, assertIndexInRange} from '../util/assert';
|
||||
|
||||
import {assertComponentType} from './assert';
|
||||
import {getComponentDef} from './definition';
|
||||
import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di';
|
||||
|
@ -173,12 +172,13 @@ export function createRootComponentView(
|
|||
rNode: RElement|null, def: ComponentDef<any>, rootView: LView,
|
||||
rendererFactory: RendererFactory3, hostRenderer: Renderer3, sanitizer?: Sanitizer|null): LView {
|
||||
const tView = rootView[TVIEW];
|
||||
ngDevMode && assertIndexInRange(rootView, 0 + HEADER_OFFSET);
|
||||
rootView[0 + HEADER_OFFSET] = rNode;
|
||||
const index = HEADER_OFFSET;
|
||||
ngDevMode && assertIndexInRange(rootView, index);
|
||||
rootView[index] = rNode;
|
||||
// '#host' is added here as we don't know the real host DOM name (we don't want to read it) and at
|
||||
// the same time we want to communicate the the debug `TNode` that this is a special `TNode`
|
||||
// representing a host element.
|
||||
const tNode = getOrCreateTNode(tView, 0, TNodeType.Element, '#host', null);
|
||||
const tNode: TElementNode = getOrCreateTNode(tView, index, TNodeType.Element, '#host', null);
|
||||
const mergedAttrs = tNode.mergedAttrs = def.hostAttrs;
|
||||
if (mergedAttrs !== null) {
|
||||
computeStaticStyling(tNode, mergedAttrs, true);
|
||||
|
@ -196,7 +196,7 @@ export function createRootComponentView(
|
|||
const viewRenderer = rendererFactory.createRenderer(rNode, def);
|
||||
const componentView = createLView(
|
||||
rootView, getOrCreateTComponentView(def), null,
|
||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[HEADER_OFFSET], tNode,
|
||||
def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways, rootView[index], tNode,
|
||||
rendererFactory, viewRenderer, sanitizer || null, null);
|
||||
|
||||
if (tView.firstCreatePass) {
|
||||
|
@ -208,7 +208,7 @@ export function createRootComponentView(
|
|||
addToViewTree(rootView, componentView);
|
||||
|
||||
// Store component view at node index, with node as the HOST
|
||||
return rootView[HEADER_OFFSET] = componentView;
|
||||
return rootView[index] = componentView;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,8 +237,7 @@ export function createRootComponent<T>(
|
|||
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
||||
if (tView.firstCreatePass &&
|
||||
(componentDef.hostBindings !== null || componentDef.hostAttrs !== null)) {
|
||||
const elementIndex = rootTNode.index - HEADER_OFFSET;
|
||||
setSelectedIndex(elementIndex);
|
||||
setSelectedIndex(rootTNode.index);
|
||||
|
||||
const rootTView = rootLView[TVIEW];
|
||||
addHostBindingsToExpandoInstructions(rootTView, componentDef);
|
||||
|
|
|
@ -27,7 +27,7 @@ import {createLView, createTView, locateHostElement, renderView} from './instruc
|
|||
import {ComponentDef} from './interfaces/definition';
|
||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode} from './interfaces/node';
|
||||
import {domRendererFactory3, RendererFactory3, RNode} from './interfaces/renderer';
|
||||
import {LView, LViewFlags, TViewType} from './interfaces/view';
|
||||
import {HEADER_OFFSET, LView, LViewFlags, TViewType} from './interfaces/view';
|
||||
import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces';
|
||||
import {createElementNode, writeDirectClass} from './node_manipulation';
|
||||
import {extractAttrsAndClassesFromSelector, stringifyCSSSelectorList} from './node_selector_matcher';
|
||||
|
@ -192,7 +192,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
|
|||
}
|
||||
}
|
||||
|
||||
tElementNode = getTNode(rootTView, 0) as TElementNode;
|
||||
tElementNode = getTNode(rootTView, HEADER_OFFSET) as TElementNode;
|
||||
|
||||
if (projectableNodes !== undefined) {
|
||||
const projection: (TNode|RNode[]|null)[] = tElementNode.projection = [];
|
||||
|
|
|
@ -14,7 +14,7 @@ import {LContext, MONKEY_PATCH_KEY_NAME} from './interfaces/context';
|
|||
import {TNode, TNodeFlags} from './interfaces/node';
|
||||
import {RElement, RNode} from './interfaces/renderer';
|
||||
import {CONTEXT, HEADER_OFFSET, HOST, LView, TVIEW} from './interfaces/view';
|
||||
import {getComponentLViewByIndex, getNativeByTNodeOrNull, readPatchedData, unwrapRNode} from './util/view_utils';
|
||||
import {getComponentLViewByIndex, readPatchedData, unwrapRNode} from './util/view_utils';
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ export function setMaskBit(hasChange: boolean) {
|
|||
export function applyI18n(tView: TView, lView: LView, index: number) {
|
||||
if (changeMaskCounter > 0) {
|
||||
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||
const tI18n = tView.data[index + HEADER_OFFSET] as TI18n | I18nUpdateOpCodes;
|
||||
const tI18n = tView.data[index] as TI18n | I18nUpdateOpCodes;
|
||||
// When `index` points to an `ɵɵi18nAttributes` then we have an array otherwise `TI18n`
|
||||
const updateOpCodes: I18nUpdateOpCodes =
|
||||
Array.isArray(tI18n) ? tI18n as I18nUpdateOpCodes : (tI18n as TI18n).update;
|
||||
|
@ -195,8 +195,8 @@ export function applyMutableOpCodes(
|
|||
// This code is used for ICU expressions only, since we don't support
|
||||
// directives/components in ICUs, we don't need to worry about inputs here
|
||||
setElementAttribute(
|
||||
renderer, getNativeByIndex(elementNodeIndex - HEADER_OFFSET, lView) as RElement, null,
|
||||
null, attrName, attrValue, null);
|
||||
renderer, getNativeByIndex(elementNodeIndex, lView) as RElement, null, null, attrName,
|
||||
attrValue, null);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unable to determine the type of mutate operation for "${opCode}"`);
|
||||
|
@ -281,7 +281,7 @@ export function applyUpdateOpCodes(
|
|||
const propName = updateOpCodes[++j] as string;
|
||||
const sanitizeFn = updateOpCodes[++j] as SanitizerFn | null;
|
||||
const tNodeOrTagName = tView.data[nodeIndex] as TNode | string;
|
||||
ngDevMode && assertDefined(tNodeOrTagName, 'Expecting TNode or string');
|
||||
ngDevMode && assertDefined(tNodeOrTagName, 'Experting TNode or string');
|
||||
if (typeof tNodeOrTagName === 'string') {
|
||||
// IF we don't have a `TNode`, then we are an element in ICU (as ICU content does
|
||||
// not have TNode), in which case we know that there are no directives, and hence
|
||||
|
|
|
@ -132,7 +132,7 @@ export function i18nStartFirstCreatePass(
|
|||
}
|
||||
}
|
||||
|
||||
tView.data[index + HEADER_OFFSET] = <TI18n>{
|
||||
tView.data[index] = <TI18n>{
|
||||
create: createOpCodes,
|
||||
update: updateOpCodes,
|
||||
};
|
||||
|
@ -247,11 +247,11 @@ export function i18nAttributesFirstPass(
|
|||
// Even indexes are text (including bindings)
|
||||
const hasBinding = !!value.match(BINDING_REGEXP);
|
||||
if (hasBinding) {
|
||||
if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
|
||||
if (tView.firstCreatePass && tView.data[index] === null) {
|
||||
generateBindingUpdateOpCodes(updateOpCodes, value, previousElementIndex, attrName);
|
||||
}
|
||||
} else {
|
||||
const tNode = getTNode(tView, previousElementIndex - HEADER_OFFSET);
|
||||
const tNode = getTNode(tView, previousElementIndex);
|
||||
// Set attributes for Elements only, for other types (like ElementContainer),
|
||||
// only set inputs below
|
||||
if (tNode.type & TNodeType.AnyRNode) {
|
||||
|
@ -262,9 +262,7 @@ export function i18nAttributesFirstPass(
|
|||
if (dataValue) {
|
||||
setInputsForProperty(tView, lView, dataValue, attrName, value);
|
||||
if (ngDevMode) {
|
||||
const element =
|
||||
getNativeByIndex(previousElementIndex - HEADER_OFFSET, lView) as RElement |
|
||||
RComment;
|
||||
const element = getNativeByIndex(previousElementIndex, lView) as RElement | RComment;
|
||||
setNgReflectProperties(lView, element, tNode.type, dataValue, value);
|
||||
}
|
||||
}
|
||||
|
@ -273,8 +271,8 @@ export function i18nAttributesFirstPass(
|
|||
}
|
||||
}
|
||||
|
||||
if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
|
||||
tView.data[index + HEADER_OFFSET] = updateOpCodes;
|
||||
if (tView.firstCreatePass && tView.data[index] === null) {
|
||||
tView.data[index] = updateOpCodes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,25 +327,6 @@ export function generateBindingUpdateOpCodes(
|
|||
return mask;
|
||||
}
|
||||
|
||||
function getBindingMask(icuExpression: IcuExpression, mask = 0): number {
|
||||
mask = mask | toMaskBit(icuExpression.mainBinding);
|
||||
let match;
|
||||
for (let i = 0; i < icuExpression.values.length; i++) {
|
||||
const valueArr = icuExpression.values[i];
|
||||
for (let j = 0; j < valueArr.length; j++) {
|
||||
const value = valueArr[j];
|
||||
if (typeof value === 'string') {
|
||||
while (match = BINDING_REGEXP.exec(value)) {
|
||||
mask = mask | toMaskBit(parseInt(match[1], 10));
|
||||
}
|
||||
} else {
|
||||
mask = getBindingMask(value as IcuExpression, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert binding index to mask bit.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import {assertGreaterThan} from '../../util/assert';
|
||||
import {assertIndexInDeclRange} from '../assert';
|
||||
import {executeCheckHooks, executeInitAndCheckHooks} from '../hooks';
|
||||
import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view';
|
||||
import {FLAGS, InitPhaseState, LView, LViewFlags, TView} from '../interfaces/view';
|
||||
import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelectedIndex} from '../state';
|
||||
|
||||
|
||||
|
@ -42,7 +42,7 @@ export function ɵɵadvance(delta: number): void {
|
|||
|
||||
export function selectIndexInternal(
|
||||
tView: TView, lView: LView, index: number, checkNoChangesMode: boolean) {
|
||||
ngDevMode && assertIndexInDeclRange(lView, index + HEADER_OFFSET);
|
||||
ngDevMode && assertIndexInDeclRange(lView, index);
|
||||
|
||||
// Flush the initial hooks for elements in the view that have been added up to this point.
|
||||
// PERF WARNING: do NOT extract this to a separate function without running benchmarks
|
||||
|
|
|
@ -83,7 +83,8 @@ export function ɵɵelementStart(
|
|||
const renderer = lView[RENDERER];
|
||||
const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace());
|
||||
const tNode = tView.firstCreatePass ?
|
||||
elementStartFirstCreatePass(index, tView, lView, native, name, attrsIndex, localRefsIndex) :
|
||||
elementStartFirstCreatePass(
|
||||
adjustedIndex, tView, lView, native, name, attrsIndex, localRefsIndex) :
|
||||
tView.data[adjustedIndex] as TElementNode;
|
||||
setCurrentTNode(tNode, true);
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ export function ɵɵelementContainerStart(
|
|||
'element containers should be created before any bindings');
|
||||
|
||||
const tNode = tView.firstCreatePass ?
|
||||
elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) :
|
||||
elementContainerStartFirstCreatePass(
|
||||
adjustedIndex, tView, lView, attrsIndex, localRefsIndex) :
|
||||
tView.data[adjustedIndex] as TElementContainerNode;
|
||||
setCurrentTNode(tNode, true);
|
||||
|
||||
|
|
|
@ -49,15 +49,16 @@ export function ɵɵi18nStart(
|
|||
index: number, messageIndex: number, subTemplateIndex: number = -1): void {
|
||||
const tView = getTView();
|
||||
const lView = getLView();
|
||||
const adjustedIndex = HEADER_OFFSET + index;
|
||||
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||
const message = getConstant<string>(tView.consts, messageIndex)!;
|
||||
const parentTNode = getCurrentParentTNode() as TElementNode | null;
|
||||
if (tView.firstCreatePass) {
|
||||
i18nStartFirstCreatePass(
|
||||
tView, parentTNode === null ? 0 : parentTNode.index, lView, index, message,
|
||||
tView, parentTNode === null ? 0 : parentTNode.index, lView, adjustedIndex, message,
|
||||
subTemplateIndex);
|
||||
}
|
||||
const tI18n = tView.data[HEADER_OFFSET + index] as TI18n;
|
||||
const tI18n = tView.data[adjustedIndex] as TI18n;
|
||||
const sameViewParentTNode = parentTNode === lView[T_HOST] ? null : parentTNode;
|
||||
const parentRNode = getClosestRElement(tView, sameViewParentTNode, lView);
|
||||
// If `parentTNode` is an `ElementContainer` than it has `<!--ng-container--->`.
|
||||
|
@ -125,7 +126,7 @@ export function ɵɵi18nAttributes(index: number, attrsIndex: number): void {
|
|||
const tView = getTView();
|
||||
ngDevMode && assertDefined(tView, `tView should be defined`);
|
||||
const attrs = getConstant<string[]>(tView.consts, attrsIndex)!;
|
||||
i18nAttributesFirstPass(lView, tView, index, attrs);
|
||||
i18nAttributesFirstPass(lView, tView, index + HEADER_OFFSET, attrs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,7 +155,7 @@ export function ɵɵi18nExp<T>(value: T): typeof ɵɵi18nExp {
|
|||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵi18nApply(index: number) {
|
||||
applyI18n(getTView(), getLView(), index);
|
||||
applyI18n(getTView(), getLView(), index + HEADER_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -676,18 +676,3 @@ export class LContainerDebug implements ILContainerDebug {
|
|||
return toDebug(this._raw_lContainer[NEXT]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an `LView` value if found.
|
||||
*
|
||||
* @param value `LView` if any
|
||||
*/
|
||||
export function readLViewValue(value: any): LView|null {
|
||||
while (Array.isArray(value)) {
|
||||
// This check is not quite right, as it does not take into account `StylingContext`
|
||||
// This is why it is in debug, not in util.ts
|
||||
if (value.length >= HEADER_OFFSET - 1) return value as LView;
|
||||
value = value[HOST];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import {newArray} from '../../util/array_utils';
|
||||
import {TAttributes, TElementNode, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {ProjectionSlots} from '../interfaces/projection';
|
||||
import {DECLARATION_COMPONENT_VIEW, T_HOST} from '../interfaces/view';
|
||||
import {DECLARATION_COMPONENT_VIEW, HEADER_OFFSET, T_HOST} from '../interfaces/view';
|
||||
import {applyProjection} from '../node_manipulation';
|
||||
import {getProjectAsAttrValue, isNodeMatchingSelectorList, isSelectorInSelectorList} from '../node_selector_matcher';
|
||||
import {getLView, getTView, setCurrentTNodeAsNotParent} from '../state';
|
||||
|
@ -120,7 +120,7 @@ export function ɵɵprojection(
|
|||
const lView = getLView();
|
||||
const tView = getTView();
|
||||
const tProjectionNode =
|
||||
getOrCreateTNode(tView, nodeIndex, TNodeType.Projection, null, attrs || null);
|
||||
getOrCreateTNode(tView, HEADER_OFFSET + nodeIndex, TNodeType.Projection, null, attrs || null);
|
||||
|
||||
// We can't use viewData[HOST_NODE] because projection nodes can be nested in embedded views.
|
||||
if (tProjectionNode.projection === null) tProjectionNode.projection = selectorIndex;
|
||||
|
|
|
@ -12,7 +12,7 @@ import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../me
|
|||
import {ViewEncapsulation} from '../../metadata/view';
|
||||
import {validateAgainstEventAttributes, validateAgainstEventProperties} from '../../sanitization/sanitization';
|
||||
import {Sanitizer} from '../../sanitization/sanitizer';
|
||||
import {assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertIndexInRange, assertLessThan, assertNotEqual, assertNotSame, assertSame, assertString} from '../../util/assert';
|
||||
import {assertDefined, assertDomNode, assertEqual, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertLessThan, assertNotEqual, assertNotSame, assertSame, assertString} from '../../util/assert';
|
||||
import {createNamedArrayType} from '../../util/named_array_type';
|
||||
import {initNgDevMode} from '../../util/ng_dev_mode';
|
||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
|
||||
|
@ -214,12 +214,14 @@ export function getOrCreateTNode(
|
|||
export function getOrCreateTNode(
|
||||
tView: TView, index: number, type: TNodeType, name: string|null, attrs: TAttributes|null):
|
||||
TElementNode&TContainerNode&TElementContainerNode&TProjectionNode&TIcuContainerNode {
|
||||
ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
|
||||
// `view_engine_compatibility` for additional context.
|
||||
assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
|
||||
// Keep this function short, so that the VM will inline it.
|
||||
ngDevMode && assertPureTNodeType(type);
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
let tNode = tView.data[adjustedIndex] as TNode;
|
||||
let tNode = tView.data[index] as TNode;
|
||||
if (tNode === null) {
|
||||
tNode = createTNodeAtIndex(tView, adjustedIndex, type, name, attrs);
|
||||
tNode = createTNodeAtIndex(tView, index, type, name, attrs);
|
||||
if (isInI18nBlock()) {
|
||||
// If we are in i18n block then all elements should be pre declared through `Placeholder`
|
||||
// See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
|
||||
|
@ -234,7 +236,7 @@ export function getOrCreateTNode(
|
|||
const parent = getCurrentParentTNode();
|
||||
tNode.injectorIndex = parent === null ? -1 : parent.injectorIndex;
|
||||
ngDevMode && assertTNodeForTView(tNode, tView);
|
||||
ngDevMode && assertEqual(index + HEADER_OFFSET, tNode.index, 'Expecting same index');
|
||||
ngDevMode && assertEqual(index, tNode.index, 'Expecting same index');
|
||||
}
|
||||
setCurrentTNode(tNode, true);
|
||||
return tNode as TElementNode & TContainerNode & TElementContainerNode & TProjectionNode &
|
||||
|
@ -242,14 +244,13 @@ export function getOrCreateTNode(
|
|||
}
|
||||
|
||||
export function createTNodeAtIndex(
|
||||
tView: TView, adjustedIndex: number, type: TNodeType, name: string|null,
|
||||
attrs: TAttributes|null) {
|
||||
tView: TView, index: number, type: TNodeType, name: string|null, attrs: TAttributes|null) {
|
||||
const currentTNode = getCurrentTNodePlaceholderOk();
|
||||
const isParent = isCurrentTNodeParent();
|
||||
const parent = isParent ? currentTNode : currentTNode && currentTNode.parent;
|
||||
// Parents cannot cross component boundaries because components will be used in multiple places.
|
||||
const tNode = tView.data[adjustedIndex] =
|
||||
createTNode(tView, parent as TElementNode | TContainerNode, type, adjustedIndex, name, attrs);
|
||||
const tNode = tView.data[index] =
|
||||
createTNode(tView, parent as TElementNode | TContainerNode, type, index, name, attrs);
|
||||
// Assign a pointer to the first child node of a given view. The first node is not always the one
|
||||
// at index 0, in case of i18n, index 0 can be the instruction `i18nStart` and the first node has
|
||||
// the index 1 or more, so we can't just check node index.
|
||||
|
@ -546,7 +547,7 @@ function executeTemplate<T>(
|
|||
if (rf & RenderFlags.Update && lView.length > HEADER_OFFSET) {
|
||||
// When we're updating, inherently select 0 so we don't
|
||||
// have to generate that instruction for most update blocks.
|
||||
selectIndexInternal(tView, lView, 0, isInCheckNoChangesMode());
|
||||
selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
|
||||
}
|
||||
templateFn(rf, context);
|
||||
} finally {
|
||||
|
@ -810,7 +811,7 @@ export function storeCleanupWithContext(
|
|||
* @param tView `TView` to which this `TNode` belongs (used only in `ngDevMode`)
|
||||
* @param tParent Parent `TNode`
|
||||
* @param type The type of the node
|
||||
* @param adjustedIndex The index of the TNode in TView.data, adjusted for HEADER_OFFSET
|
||||
* @param index The index of the TNode in TView.data, adjusted for HEADER_OFFSET
|
||||
* @param tagName The tag name of the node
|
||||
* @param attrs The attributes defined on this node
|
||||
* @param tViews Any TViews attached to this node
|
||||
|
@ -818,25 +819,28 @@ export function storeCleanupWithContext(
|
|||
*/
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Container,
|
||||
adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TContainerNode;
|
||||
index: number, tagName: string|null, attrs: TAttributes|null): TContainerNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Element|TNodeType.Text,
|
||||
adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TElementNode;
|
||||
index: number, tagName: string|null, attrs: TAttributes|null): TElementNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.ElementContainer,
|
||||
adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TElementContainerNode;
|
||||
index: number, tagName: string|null, attrs: TAttributes|null): TElementContainerNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Icu,
|
||||
adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TIcuContainerNode;
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Icu, index: number,
|
||||
tagName: string|null, attrs: TAttributes|null): TIcuContainerNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType.Projection,
|
||||
adjustedIndex: number, tagName: string|null, attrs: TAttributes|null): TProjectionNode;
|
||||
index: number, tagName: string|null, attrs: TAttributes|null): TProjectionNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, adjustedIndex: number,
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, index: number,
|
||||
tagName: string|null, attrs: TAttributes|null): TNode;
|
||||
export function createTNode(
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, adjustedIndex: number,
|
||||
tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, index: number,
|
||||
value: string|null, attrs: TAttributes|null): TNode {
|
||||
ngDevMode && index !== 0 && // 0 are bogus nodes and they are OK. See `createContainerRef` in
|
||||
// `view_engine_compatibility` for additional context.
|
||||
assertGreaterThanOrEqual(index, HEADER_OFFSET, 'TNodes can\'t be in the LView header.');
|
||||
ngDevMode && assertNotSame(attrs, undefined, '\'undefined\' is not valid value for \'attrs\'');
|
||||
ngDevMode && ngDevMode.tNode++;
|
||||
ngDevMode && tParent && assertTNodeForTView(tParent, tView);
|
||||
|
@ -845,7 +849,7 @@ export function createTNode(
|
|||
new TNodeDebug(
|
||||
tView, // tView_: TView
|
||||
type, // type: TNodeType
|
||||
adjustedIndex, // index: number
|
||||
index, // index: number
|
||||
null, // insertBeforeIndex: null|-1|number|number[]
|
||||
injectorIndex, // injectorIndex: number
|
||||
-1, // directiveStart: number
|
||||
|
@ -877,10 +881,10 @@ export function createTNode(
|
|||
0 as any, // styleBindings: TStylingRange;
|
||||
) :
|
||||
{
|
||||
type: type,
|
||||
index: adjustedIndex,
|
||||
type,
|
||||
index,
|
||||
insertBeforeIndex: null,
|
||||
injectorIndex: injectorIndex,
|
||||
injectorIndex,
|
||||
directiveStart: -1,
|
||||
directiveEnd: -1,
|
||||
directiveStylingLast: -1,
|
||||
|
@ -1213,13 +1217,12 @@ export function resolveDirectives(
|
|||
// We will push the actual hook function into this array later during dir instantiation.
|
||||
// We cannot do it now because we must ensure hooks are registered in the same
|
||||
// order that directives are created (i.e. injection order).
|
||||
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index - HEADER_OFFSET);
|
||||
(tView.preOrderHooks || (tView.preOrderHooks = [])).push(tNode.index);
|
||||
preOrderHooksFound = true;
|
||||
}
|
||||
|
||||
if (!preOrderCheckHooksFound && (lifeCycleHooks.ngOnChanges || lifeCycleHooks.ngDoCheck)) {
|
||||
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = []))
|
||||
.push(tNode.index - HEADER_OFFSET);
|
||||
(tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])).push(tNode.index);
|
||||
preOrderCheckHooksFound = true;
|
||||
}
|
||||
|
||||
|
@ -1325,7 +1328,7 @@ function invokeDirectivesHostBindings(tView: TView, lView: LView, tNode: TNode)
|
|||
const end = tNode.directiveEnd;
|
||||
const expando = tView.expandoInstructions!;
|
||||
const firstCreatePass = tView.firstCreatePass;
|
||||
const elementIndex = tNode.index - HEADER_OFFSET;
|
||||
const elementIndex = tNode.index;
|
||||
const currentDirectiveIndex = getCurrentDirectiveIndex();
|
||||
try {
|
||||
setSelectedIndex(elementIndex);
|
||||
|
@ -1373,7 +1376,7 @@ export function generateExpandoInstructionBlock(
|
|||
// Important: In JS `-x` and `0-x` is not the same! If `x===0` then `-x` will produce `-0` which
|
||||
// requires non standard math arithmetic and it can prevent VM optimizations.
|
||||
// `0-0` will always produce `0` and will not cause a potential deoptimization in VM.
|
||||
const elementIndex = HEADER_OFFSET - tNode.index;
|
||||
const elementIndex = 0 - tNode.index;
|
||||
const providerStartIndex = tNode.providerIndexes & TNodeProviderIndexes.ProvidersStartIndexMask;
|
||||
const providerCount = tView.data.length - providerStartIndex;
|
||||
(tView.expandoInstructions || (tView.expandoInstructions = []))
|
||||
|
@ -2087,7 +2090,7 @@ export function setInputsForProperty(
|
|||
export function textBindingInternal(lView: LView, index: number, value: string): void {
|
||||
ngDevMode && assertString(value, 'Value should be a string');
|
||||
ngDevMode && assertNotSame(value, NO_CHANGE as any, 'value should not be NO_CHANGE');
|
||||
ngDevMode && assertIndexInRange(lView, index + HEADER_OFFSET);
|
||||
ngDevMode && assertIndexInRange(lView, index);
|
||||
const element = getNativeByIndex(index, lView) as any as RText;
|
||||
ngDevMode && assertDefined(element, 'native element should exist');
|
||||
updateTextNode(lView[RENDERER], element, value);
|
||||
|
|
|
@ -14,12 +14,11 @@ import {load} from '../util/view_utils';
|
|||
export function store<T>(tView: TView, lView: LView, index: number, value: T): void {
|
||||
// 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;
|
||||
tView.blueprint[adjustedIndex] = null;
|
||||
if (index >= tView.data.length) {
|
||||
tView.data[index] = null;
|
||||
tView.blueprint[index] = null;
|
||||
}
|
||||
lView[adjustedIndex] = value;
|
||||
lView[index] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,5 +33,5 @@ export function store<T>(tView: TView, lView: LView, index: number, value: T): v
|
|||
*/
|
||||
export function ɵɵreference<T>(index: number) {
|
||||
const contextLView = getContextLView();
|
||||
return load<T>(contextLView, index);
|
||||
return load<T>(contextLView, HEADER_OFFSET + index);
|
||||
}
|
||||
|
|
|
@ -17,14 +17,13 @@ import {DirectiveDef} from '../interfaces/definition';
|
|||
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {RElement, Renderer3} from '../interfaces/renderer';
|
||||
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
|
||||
import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view';
|
||||
import {LView, RENDERER, TData, TView} from '../interfaces/view';
|
||||
import {applyStyling} from '../node_manipulation';
|
||||
import {getCurrentDirectiveDef, getLView, getSelectedIndex, getTView, incrementBindingIndex} from '../state';
|
||||
import {insertTStylingBinding} from '../styling/style_binding_list';
|
||||
import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {getNativeByIndex} from '../util/view_utils';
|
||||
|
||||
import {setDirectiveInputsWhichShadowsStyling} from './property';
|
||||
|
||||
|
||||
|
@ -174,7 +173,7 @@ export function checkStylingProperty(
|
|||
stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
|
||||
}
|
||||
if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
|
||||
const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
||||
const tNode = tView.data[getSelectedIndex()] as TNode;
|
||||
updateStyling(
|
||||
tView, tNode, lView, lView[RENDERER], prop,
|
||||
lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
|
||||
|
@ -204,7 +203,7 @@ export function checkStylingMap(
|
|||
if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
|
||||
// `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
|
||||
// if so as not to read unnecessarily.
|
||||
const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
||||
const tNode = tView.data[getSelectedIndex()] as TNode;
|
||||
if (hasStylingInputShadow(tNode, isClassBased) && !isInHostBindings(tView, bindingIndex)) {
|
||||
if (ngDevMode) {
|
||||
// verify that if we are shadowing then `TData` is appropriately marked so that we skip
|
||||
|
@ -271,7 +270,8 @@ function stylingFirstUpdatePass(
|
|||
// itself to the list.
|
||||
// `getSelectedIndex()` should be here (rather than in instruction) so that it is guarded by the
|
||||
// if so as not to read unnecessarily.
|
||||
const tNode = tData[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
||||
const tNode = tData[getSelectedIndex()] as TNode;
|
||||
ngDevMode && assertDefined(tNode, 'TNode expected');
|
||||
const isHostBindings = isInHostBindings(tView, bindingIndex);
|
||||
if (hasStylingInputShadow(tNode, isClassBased) && tStylingKey === null && !isHostBindings) {
|
||||
// `tStylingKey === null` implies that we are either `[style]` or `[class]` binding.
|
||||
|
|
|
@ -73,9 +73,9 @@ export function ɵɵtemplate(
|
|||
const tView = getTView();
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
|
||||
const tNode = tView.firstCreatePass ?
|
||||
templateFirstCreatePass(
|
||||
index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
|
||||
const tNode = tView.firstCreatePass ? templateFirstCreatePass(
|
||||
adjustedIndex, tView, lView, templateFn, decls, vars,
|
||||
tagName, attrsIndex, localRefsIndex) :
|
||||
tView.data[adjustedIndex] as TContainerNode;
|
||||
setCurrentTNode(tNode, false);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export function ɵɵtext(index: number, value: string = ''): void {
|
|||
ngDevMode && assertIndexInRange(lView, adjustedIndex);
|
||||
|
||||
const tNode = tView.firstCreatePass ?
|
||||
getOrCreateTNode(tView, index, TNodeType.Text, value, null) :
|
||||
getOrCreateTNode(tView, adjustedIndex, TNodeType.Text, value, null) :
|
||||
tView.data[adjustedIndex] as TElementNode;
|
||||
|
||||
const textNative = lView[adjustedIndex] = createTextNode(lView[RENDERER], value);
|
||||
|
|
|
@ -47,7 +47,13 @@ export const DECLARATION_COMPONENT_VIEW = 16;
|
|||
export const DECLARATION_LCONTAINER = 17;
|
||||
export const PREORDER_HOOK_FLAGS = 18;
|
||||
export const QUERIES = 19;
|
||||
/** Size of LView's header. Necessary to adjust for it when setting slots. */
|
||||
/**
|
||||
* Size of LView's header. Necessary to adjust for it when setting slots.
|
||||
*
|
||||
* IMPORTANT: `HEADER_OFFSET` should only be referred to the in the `ɵɵ*` instructions to translate
|
||||
* instruction index into `LView` index. All other indexes should be in the `LView` index space and
|
||||
* there should be no need to refer to `HEADER_OFFSET` anywhere else.
|
||||
*/
|
||||
export const HEADER_OFFSET = 20;
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ export function ɵɵpipe(index: number, pipeName: string): any {
|
|||
const previousIncludeViewProviders = setIncludeViewProviders(false);
|
||||
const pipeInstance = pipeFactory();
|
||||
setIncludeViewProviders(previousIncludeViewProviders);
|
||||
store(tView, getLView(), index, pipeInstance);
|
||||
store(tView, getLView(), adjustedIndex, pipeInstance);
|
||||
return pipeInstance;
|
||||
} finally {
|
||||
// we have to restore the injector implementation in finally, just in case the creation of the
|
||||
|
@ -96,11 +96,12 @@ function getPipeDef(name: string, registry: PipeDefList|null): PipeDef<any> {
|
|||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any {
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
const lView = getLView();
|
||||
const pipeInstance = load<PipeTransform>(lView, index);
|
||||
const pipeInstance = load<PipeTransform>(lView, adjustedIndex);
|
||||
return unwrapValue(
|
||||
lView,
|
||||
isPure(lView, index) ?
|
||||
isPure(lView, adjustedIndex) ?
|
||||
pureFunction1Internal(
|
||||
lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
|
||||
pipeInstance.transform(v1));
|
||||
|
@ -120,11 +121,12 @@ export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any {
|
|||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpipeBind2(index: number, slotOffset: number, v1: any, v2: any): any {
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
const lView = getLView();
|
||||
const pipeInstance = load<PipeTransform>(lView, index);
|
||||
const pipeInstance = load<PipeTransform>(lView, adjustedIndex);
|
||||
return unwrapValue(
|
||||
lView,
|
||||
isPure(lView, index) ?
|
||||
isPure(lView, adjustedIndex) ?
|
||||
pureFunction2Internal(
|
||||
lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
|
||||
pipeInstance.transform(v1, v2));
|
||||
|
@ -145,13 +147,14 @@ export function ɵɵpipeBind2(index: number, slotOffset: number, v1: any, v2: an
|
|||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpipeBind3(index: number, slotOffset: number, v1: any, v2: any, v3: any): any {
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
const lView = getLView();
|
||||
const pipeInstance = load<PipeTransform>(lView, index);
|
||||
const pipeInstance = load<PipeTransform>(lView, adjustedIndex);
|
||||
return unwrapValue(
|
||||
lView,
|
||||
isPure(lView, index) ? pureFunction3Internal(
|
||||
lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1,
|
||||
v2, v3, pipeInstance) :
|
||||
isPure(lView, adjustedIndex) ? pureFunction3Internal(
|
||||
lView, getBindingRoot(), slotOffset,
|
||||
pipeInstance.transform, v1, v2, v3, pipeInstance) :
|
||||
pipeInstance.transform(v1, v2, v3));
|
||||
}
|
||||
|
||||
|
@ -172,13 +175,14 @@ export function ɵɵpipeBind3(index: number, slotOffset: number, v1: any, v2: an
|
|||
*/
|
||||
export function ɵɵpipeBind4(
|
||||
index: number, slotOffset: number, v1: any, v2: any, v3: any, v4: any): any {
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
const lView = getLView();
|
||||
const pipeInstance = load<PipeTransform>(lView, index);
|
||||
const pipeInstance = load<PipeTransform>(lView, adjustedIndex);
|
||||
return unwrapValue(
|
||||
lView,
|
||||
isPure(lView, index) ? pureFunction4Internal(
|
||||
lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1,
|
||||
v2, v3, v4, pipeInstance) :
|
||||
isPure(lView, adjustedIndex) ? pureFunction4Internal(
|
||||
lView, getBindingRoot(), slotOffset,
|
||||
pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
|
||||
pipeInstance.transform(v1, v2, v3, v4));
|
||||
}
|
||||
|
||||
|
@ -195,18 +199,19 @@ export function ɵɵpipeBind4(
|
|||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵpipeBindV(index: number, slotOffset: number, values: [any, ...any[]]): any {
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
const lView = getLView();
|
||||
const pipeInstance = load<PipeTransform>(lView, index);
|
||||
const pipeInstance = load<PipeTransform>(lView, adjustedIndex);
|
||||
return unwrapValue(
|
||||
lView,
|
||||
isPure(lView, index) ?
|
||||
isPure(lView, adjustedIndex) ?
|
||||
pureFunctionVInternal(
|
||||
lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) :
|
||||
pipeInstance.transform.apply(pipeInstance, values));
|
||||
}
|
||||
|
||||
function isPure(lView: LView, index: number): boolean {
|
||||
return (<PipeDef<any>>lView[TVIEW].data[index + HEADER_OFFSET]).pure;
|
||||
return (<PipeDef<any>>lView[TVIEW].data[index]).pure;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {assertDefined, assertEqual, assertNotEqual} from '../util/assert';
|
||||
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual} from '../util/assert';
|
||||
import {assertLViewOrUndefined, assertTNodeForTView} from './assert';
|
||||
import {DirectiveDef} from './interfaces/definition';
|
||||
import {TNode, TNodeType} from './interfaces/node';
|
||||
import {CONTEXT, DECLARATION_VIEW, LView, OpaqueViewState, TData, TVIEW, TView} from './interfaces/view';
|
||||
import {CONTEXT, DECLARATION_VIEW, HEADER_OFFSET, LView, OpaqueViewState, TData, TVIEW, TView} from './interfaces/view';
|
||||
import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces';
|
||||
import {assertTNodeType} from './node_assert';
|
||||
import {getTNode} from './util/view_utils';
|
||||
|
@ -458,13 +458,14 @@ export function enterDI(newView: LView, tNode: TNode) {
|
|||
* @returns the previously active lView;
|
||||
*/
|
||||
export function enterView(newView: LView): void {
|
||||
ngDevMode && assertNotEqual(newView[0], newView[1] as any, '????');
|
||||
ngDevMode && assertLViewOrUndefined(newView);
|
||||
const newLFrame = allocLFrame();
|
||||
if (ngDevMode) {
|
||||
assertEqual(newLFrame.isParent, true, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.lView, null, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.tView, null, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.selectedIndex, 0, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.selectedIndex, -1, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
|
||||
assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
|
||||
|
@ -498,7 +499,7 @@ function createLFrame(parent: LFrame|null): LFrame {
|
|||
isParent: true,
|
||||
lView: null!,
|
||||
tView: null!,
|
||||
selectedIndex: 0,
|
||||
selectedIndex: -1,
|
||||
contextLView: null!,
|
||||
elementDepthCount: 0,
|
||||
currentNamespace: null,
|
||||
|
@ -551,7 +552,7 @@ export function leaveView() {
|
|||
const oldLFrame = leaveViewLight();
|
||||
oldLFrame.isParent = true;
|
||||
oldLFrame.tView = null!;
|
||||
oldLFrame.selectedIndex = 0;
|
||||
oldLFrame.selectedIndex = -1;
|
||||
oldLFrame.contextLView = null!;
|
||||
oldLFrame.elementDepthCount = 0;
|
||||
oldLFrame.currentDirectiveIndex = -1;
|
||||
|
@ -599,6 +600,11 @@ export function getSelectedIndex() {
|
|||
* run if and when the provided `index` value is different from the current selected index value.)
|
||||
*/
|
||||
export function setSelectedIndex(index: number) {
|
||||
ngDevMode && index !== -1 &&
|
||||
assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Index must be past HEADER_OFFSET (or -1).');
|
||||
ngDevMode &&
|
||||
assertLessThan(
|
||||
index, instructionState.lFrame.lView.length, 'Can\'t set index passed end of LView');
|
||||
instructionState.lFrame.selectedIndex = index;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import {LContext} from '../interfaces/context';
|
|||
import {DirectiveDef} from '../interfaces/definition';
|
||||
import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node';
|
||||
import {isLView} from '../interfaces/type_checks';
|
||||
import {CLEANUP, CONTEXT, DebugNode, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view';
|
||||
import {CLEANUP, CONTEXT, DebugNode, FLAGS, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../interfaces/view';
|
||||
|
||||
import {stringifyForError} from './misc_utils';
|
||||
import {getLViewParent, getRootContext} from './view_traversal_utils';
|
||||
|
@ -387,8 +387,8 @@ export function getDebugNode(element: Element): DebugNode|null {
|
|||
const valueInLView = lView[nodeIndex];
|
||||
// this means that value in the lView is a component with its own
|
||||
// data. In this situation the TNode is not accessed at the same spot.
|
||||
const tNode = isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) :
|
||||
getTNode(lView[TVIEW], nodeIndex - HEADER_OFFSET);
|
||||
const tNode =
|
||||
isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) : getTNode(lView[TVIEW], nodeIndex);
|
||||
ngDevMode &&
|
||||
assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index');
|
||||
debugNode = buildDebugNode(tNode, lView);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {assertDefined, assertDomNode, assertGreaterThan, assertIndexInRange, assertLessThan} from '../../util/assert';
|
||||
import {assertDefined, assertDomNode, assertGreaterThan, assertGreaterThanOrEqual, assertIndexInRange, assertLessThan} from '../../util/assert';
|
||||
import {assertTNode, assertTNodeForLView} from '../assert';
|
||||
import {LContainer, TYPE} from '../interfaces/container';
|
||||
import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context';
|
||||
|
@ -78,7 +78,9 @@ export function unwrapLContainer(value: RNode|LView|LContainer): LContainer|null
|
|||
* from any containers, component views, or style contexts.
|
||||
*/
|
||||
export function getNativeByIndex(index: number, lView: LView): RNode {
|
||||
return unwrapRNode(lView[index + HEADER_OFFSET]);
|
||||
ngDevMode && assertIndexInRange(lView, index);
|
||||
ngDevMode && assertGreaterThanOrEqual(index, HEADER_OFFSET, 'Expected to be past HEADER_OFFSET');
|
||||
return unwrapRNode(lView[index]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,16 +122,16 @@ export function getNativeByTNodeOrNull(tNode: TNode|null, lView: LView): RNode|n
|
|||
// fixme(misko): The return Type should be `TNode|null`
|
||||
export function getTNode(tView: TView, index: number): TNode {
|
||||
ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
|
||||
ngDevMode && assertLessThan(index, tView.data.length - HEADER_OFFSET, 'wrong index for TNode');
|
||||
const tNode = tView.data[index + HEADER_OFFSET] as TNode;
|
||||
ngDevMode && assertLessThan(index, tView.data.length, 'wrong index for TNode');
|
||||
const tNode = tView.data[index] as TNode;
|
||||
ngDevMode && tNode !== null && assertTNode(tNode);
|
||||
return tNode;
|
||||
}
|
||||
|
||||
/** Retrieves a value from any `LView` or `TData`. */
|
||||
export function load<T>(view: LView|TData, index: number): T {
|
||||
ngDevMode && assertIndexInRange(view, index + HEADER_OFFSET);
|
||||
return view[index + HEADER_OFFSET];
|
||||
ngDevMode && assertIndexInRange(view, index);
|
||||
return view[index];
|
||||
}
|
||||
|
||||
export function getComponentLViewByIndex(nodeIndex: number, hostView: LView): LView {
|
||||
|
|
|
@ -391,8 +391,8 @@ export function createContainerRef(
|
|||
} else {
|
||||
// The TNode created here is bogus, in that it is not added to the TView. It is only created
|
||||
// to allow us to create a dynamic Comment node.
|
||||
const commentTNode = createTNode(
|
||||
hostView[TVIEW], hostTNode.parent, TNodeType.Container, hostTNode.type, null, null);
|
||||
const commentTNode =
|
||||
createTNode(hostView[TVIEW], hostTNode.parent, TNodeType.Container, 0, null, null);
|
||||
appendChild(hostView[TVIEW], hostView, commentNode, commentTNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -652,12 +652,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
const lViewDebug = lView.debug!;
|
||||
fixture.detectChanges();
|
||||
expect((fixture.nativeElement as Element).textContent).toEqual('just now');
|
||||
expect(lViewDebug.nodes.map(toTypeContent)).toEqual(['IcuContainer(<!--ICU 0:0-->)']);
|
||||
expect(lViewDebug.nodes.map(toTypeContent)).toEqual(['IcuContainer(<!--ICU 20:0-->)']);
|
||||
// We want to ensure that the ICU container does not have any content!
|
||||
// This is because the content is instance dependent and therefore can't be shared
|
||||
// across `TNode`s.
|
||||
expect(lViewDebug.nodes[0].children.map(toTypeContent)).toEqual([]);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('just now<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('just now<!--ICU 20:0-->');
|
||||
});
|
||||
|
||||
it('should support multiple ICUs', () => {
|
||||
|
@ -674,15 +674,15 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
`);
|
||||
const lView = getComponentLView(fixture.componentInstance);
|
||||
expect(lView.debug!.nodes.map(toTypeContent)).toEqual([
|
||||
'IcuContainer(<!--ICU 0:0-->)',
|
||||
'IcuContainer(<!--ICU 1:0-->)',
|
||||
'IcuContainer(<!--ICU 20:0-->)',
|
||||
'IcuContainer(<!--ICU 21:0-->)',
|
||||
]);
|
||||
// We want to ensure that the ICU container does not have any content!
|
||||
// This is because the content is instance dependent and therefore can't be shared
|
||||
// across `TNode`s.
|
||||
expect(lView.debug!.nodes[0].children.map(toTypeContent)).toEqual([]);
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual('just now<!--ICU 0:0-->Mr. Angular<!--ICU 1:0-->');
|
||||
.toEqual('just now<!--ICU 20:0-->Mr. Angular<!--ICU 21:0-->');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -778,19 +778,19 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
other {({{name}})}
|
||||
}</div>`);
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`<div>aucun <b>email</b>!<!--ICU 1:0--> - (Angular)<!--ICU 1:3--></div>`);
|
||||
.toEqual(`<div>aucun <b>email</b>!<!--ICU 21:0--> - (Angular)<!--ICU 21:3--></div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 4;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<div>4 <span title="Angular">emails</span><!--ICU 1:0--> - (Angular)<!--ICU 1:3--></div>`);
|
||||
`<div>4 <span title="Angular">emails</span><!--ICU 21:0--> - (Angular)<!--ICU 21:3--></div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 0;
|
||||
fixture.componentRef.instance.name = 'John';
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`<div>aucun <b>email</b>!<!--ICU 1:0--> - (John)<!--ICU 1:3--></div>`);
|
||||
.toEqual(`<div>aucun <b>email</b>!<!--ICU 21:0--> - (John)<!--ICU 21:3--></div>`);
|
||||
});
|
||||
|
||||
it('with custom interpolation config', () => {
|
||||
|
@ -829,9 +829,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<div>` +
|
||||
`<span>aucun <b>email</b>!<!--ICU 1:0--></span>` +
|
||||
`<span>aucun <b>email</b>!<!--ICU 21:0--></span>` +
|
||||
` - ` +
|
||||
`<span>(Angular)<!--ICU 1:3--></span>` +
|
||||
`<span>(Angular)<!--ICU 21:3--></span>` +
|
||||
`</div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 4;
|
||||
|
@ -839,9 +839,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<div>` +
|
||||
`<span>4 <span title="Angular">emails</span><!--ICU 1:0--></span>` +
|
||||
`<span>4 <span title="Angular">emails</span><!--ICU 21:0--></span>` +
|
||||
` - ` +
|
||||
`<span>(Angular)<!--ICU 1:3--></span>` +
|
||||
`<span>(Angular)<!--ICU 21:3--></span>` +
|
||||
`</div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 0;
|
||||
|
@ -850,9 +850,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<div>` +
|
||||
`<span>aucun <b>email</b>!<!--ICU 1:0--></span>` +
|
||||
`<span>aucun <b>email</b>!<!--ICU 21:0--></span>` +
|
||||
` - ` +
|
||||
`<span>(John)<!--ICU 1:3--></span>` +
|
||||
`<span>(John)<!--ICU 21:3--></span>` +
|
||||
`</div>`);
|
||||
});
|
||||
|
||||
|
@ -867,7 +867,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
other {({{name}})}
|
||||
}</span></div>`);
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`<div><span>(Angular)<!--ICU 0:0--></span><!--bindings={
|
||||
.toEqual(`<div><span>(Angular)<!--ICU 20:0--></span><!--bindings={
|
||||
"ng-reflect-ng-if": "true"
|
||||
}--></div>`);
|
||||
|
||||
|
@ -886,7 +886,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
const fixture = initWithTemplate(AppComp, `<ng-container i18n>{name, select,
|
||||
other {({{name}})}
|
||||
}</ng-container>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`(Angular)<!--ICU 1:0--><!--ng-container-->`);
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`(Angular)<!--ICU 21:0--><!--ng-container-->`);
|
||||
});
|
||||
|
||||
it('inside <ng-template>', () => {
|
||||
|
@ -921,12 +922,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
other {animals}
|
||||
}!}
|
||||
}</div>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 1:1--></div>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 21:1--></div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 4;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`<div>4 animaux<!--nested ICU 0-->!<!--ICU 1:1--></div>`);
|
||||
.toEqual(`<div>4 animaux<!--nested ICU 0-->!<!--ICU 21:1--></div>`);
|
||||
});
|
||||
|
||||
it('nested with interpolations in "other" blocks', () => {
|
||||
|
@ -946,16 +947,16 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
}!}
|
||||
other {other - {{count}}}
|
||||
}</div>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 1:1--></div>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>zero<!--ICU 21:1--></div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 2;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(`<div>2 animaux<!--nested ICU 0-->!<!--ICU 1:1--></div>`);
|
||||
.toEqual(`<div>2 animaux<!--nested ICU 0-->!<!--ICU 21:1--></div>`);
|
||||
|
||||
fixture.componentRef.instance.count = 4;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 1:1--></div>`);
|
||||
expect(fixture.nativeElement.innerHTML).toEqual(`<div>autre - 4<!--ICU 21:1--></div>`);
|
||||
});
|
||||
|
||||
it('should return the correct plural form for ICU expressions when using "ro" locale', () => {
|
||||
|
@ -988,31 +989,31 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
=other {lots of emails}
|
||||
}`);
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
|
||||
// Change detection cycle, no model changes
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 3;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 1;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 10;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('a few emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 20;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 0;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
});
|
||||
|
||||
it(`should return the correct plural form for ICU expressions when using "es" locale`, () => {
|
||||
|
@ -1039,31 +1040,31 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
=other {lots of emails}
|
||||
}`);
|
||||
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
|
||||
// Change detection cycle, no model changes
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 3;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 1;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('one email<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 10;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 20;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('lots of emails<!--ICU 20:0-->');
|
||||
|
||||
fixture.componentInstance.count = 0;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 0:0-->');
|
||||
expect(fixture.nativeElement.innerHTML).toEqual('no email<!--ICU 20:0-->');
|
||||
});
|
||||
|
||||
it('projection', () => {
|
||||
|
@ -1158,12 +1159,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||
.toContain('<my-cmp><div>ONE<!--ICU 1:0--></div><!--container--></my-cmp>');
|
||||
.toContain('<my-cmp><div>ONE<!--ICU 21:0--></div><!--container--></my-cmp>');
|
||||
|
||||
fixture.componentRef.instance.count = 2;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||
.toContain('<my-cmp><div>OTHER<!--ICU 1:0--></div><!--container--></my-cmp>');
|
||||
.toContain('<my-cmp><div>OTHER<!--ICU 21:0--></div><!--container--></my-cmp>');
|
||||
|
||||
// destroy component
|
||||
fixture.componentInstance.condition = false;
|
||||
|
@ -1175,7 +1176,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
fixture.componentInstance.count = 1;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||
.toContain('<my-cmp><div>ONE<!--ICU 1:0--></div><!--container--></my-cmp>');
|
||||
.toContain('<my-cmp><div>ONE<!--ICU 21:0--></div><!--container--></my-cmp>');
|
||||
});
|
||||
|
||||
it('with nested ICU expression and inside a container when creating a view via vcr.createEmbeddedView',
|
||||
|
@ -1247,12 +1248,12 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||
.toBe(
|
||||
'<my-cmp><div>2 animals<!--nested ICU 0-->!<!--ICU 1:1--></div><!--container--></my-cmp>');
|
||||
'<my-cmp><div>2 animals<!--nested ICU 0-->!<!--ICU 21:1--></div><!--container--></my-cmp>');
|
||||
|
||||
fixture.componentRef.instance.count = 1;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.debugElement.nativeElement.innerHTML)
|
||||
.toBe('<my-cmp><div>ONE<!--ICU 1:1--></div><!--container--></my-cmp>');
|
||||
.toBe('<my-cmp><div>ONE<!--ICU 21:1--></div><!--container--></my-cmp>');
|
||||
});
|
||||
|
||||
it('with nested containers', () => {
|
||||
|
@ -2369,13 +2370,13 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<child><div>Contenu enfant et projection depuis Parent<!--ICU 1:0--></div></child>`);
|
||||
`<child><div>Contenu enfant et projection depuis Parent<!--ICU 21:0--></div></child>`);
|
||||
|
||||
fixture.componentRef.instance.name = 'angular';
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.innerHTML)
|
||||
.toEqual(
|
||||
`<child><div>Contenu enfant et projection depuis Angular<!--ICU 1:0--></div></child>`);
|
||||
`<child><div>Contenu enfant et projection depuis Angular<!--ICU 21:0--></div></child>`);
|
||||
});
|
||||
|
||||
it(`shouldn't project deleted projections in i18n blocks`, () => {
|
||||
|
|
|
@ -54,44 +54,44 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
|
|||
describe('whose index is smaller than current nodes', () => {
|
||||
it('should update the previous insertBeforeIndex', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20),
|
||||
tPlaceholderElementNode(21),
|
||||
tPlaceholderElementNode(22),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(19));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(20));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 19, insertBeforeIndex: null}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 22, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not update the previous insertBeforeIndex if it is already set', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20, 19),
|
||||
tPlaceholderElementNode(21, 19),
|
||||
tPlaceholderElementNode(19),
|
||||
tPlaceholderElementNode(22, 21),
|
||||
tPlaceholderElementNode(23, 21),
|
||||
tPlaceholderElementNode(21),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(18));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(20));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 19, insertBeforeIndex: 18}),
|
||||
matchTNode({index: 18, insertBeforeIndex: null}),
|
||||
matchTNode({index: 22, insertBeforeIndex: 21}),
|
||||
matchTNode({index: 23, insertBeforeIndex: 21}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not update the previous insertBeforeIndex if it is created after', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20, 15),
|
||||
tPlaceholderElementNode(21, 15),
|
||||
tPlaceholderElementNode(15),
|
||||
tPlaceholderElementNode(25, 20),
|
||||
tPlaceholderElementNode(26, 20),
|
||||
tPlaceholderElementNode(20),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(18));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tPlaceholderElementNode(23));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 15}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 15}),
|
||||
matchTNode({index: 15, insertBeforeIndex: null}),
|
||||
matchTNode({index: 18, insertBeforeIndex: null}),
|
||||
matchTNode({index: 25, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 26, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: null}),
|
||||
matchTNode({index: 23, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -116,44 +116,44 @@ describe('addTNodeAndUpdateInsertBeforeIndex', () => {
|
|||
describe('whose index is smaller than current nodes', () => {
|
||||
it('should update the previous insertBeforeIndex', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20),
|
||||
tPlaceholderElementNode(21),
|
||||
tPlaceholderElementNode(22),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(19));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(20));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 19, insertBeforeIndex: null}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 22, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not update the previous insertBeforeIndex if it is already set', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20, 19),
|
||||
tPlaceholderElementNode(21, 19),
|
||||
tPlaceholderElementNode(19),
|
||||
tPlaceholderElementNode(22, 21),
|
||||
tPlaceholderElementNode(23, 21),
|
||||
tPlaceholderElementNode(21),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(18));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(20));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 19}),
|
||||
matchTNode({index: 19, insertBeforeIndex: 18}),
|
||||
matchTNode({index: 18, insertBeforeIndex: null}),
|
||||
matchTNode({index: 22, insertBeforeIndex: 21}),
|
||||
matchTNode({index: 23, insertBeforeIndex: 21}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not update the previous insertBeforeIndex if it is created after', () => {
|
||||
const previousTNodes: TNode[] = [
|
||||
tPlaceholderElementNode(20, 15),
|
||||
tPlaceholderElementNode(21, 15),
|
||||
tPlaceholderElementNode(15),
|
||||
tPlaceholderElementNode(25, 20),
|
||||
tPlaceholderElementNode(26, 20),
|
||||
tPlaceholderElementNode(20),
|
||||
];
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(18));
|
||||
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tI18NTextNode(23));
|
||||
expect(previousTNodes).toEqual([
|
||||
matchTNode({index: 20, insertBeforeIndex: 15}),
|
||||
matchTNode({index: 21, insertBeforeIndex: 15}),
|
||||
matchTNode({index: 15, insertBeforeIndex: 18}),
|
||||
matchTNode({index: 18, insertBeforeIndex: null}),
|
||||
matchTNode({index: 25, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 26, insertBeforeIndex: 20}),
|
||||
matchTNode({index: 20, insertBeforeIndex: 23}),
|
||||
matchTNode({index: 23, insertBeforeIndex: null}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('i18n_parse', () => {
|
|||
// 21: Binding for ICU |
|
||||
// ----- EXPANDO -----
|
||||
// 22: null | #text(before|)
|
||||
// 23: TIcu | <!-- ICU 0:0 -->
|
||||
// 23: TIcu | <!-- ICU 20:0 -->
|
||||
// 24: null | currently selected ICU case
|
||||
// 25: null | #text(caseA)
|
||||
// 26: null | #text(otherCase)
|
||||
|
@ -59,7 +59,7 @@ describe('i18n_parse', () => {
|
|||
create: matchDebug([
|
||||
'lView[22] = document.createText("before|");',
|
||||
'parent.appendChild(lView[22]);',
|
||||
'lView[23] = document.createComment("ICU 0:0");',
|
||||
'lView[23] = document.createComment("ICU 20:0");',
|
||||
'parent.appendChild(lView[23]);',
|
||||
'lView[27] = document.createText("|after");',
|
||||
'parent.appendChild(lView[27]);',
|
||||
|
@ -95,22 +95,22 @@ describe('i18n_parse', () => {
|
|||
|
||||
fixture.apply(() => {
|
||||
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
|
||||
expect(fixture.host.innerHTML).toEqual('before|<!--ICU 0:0-->|after');
|
||||
expect(fixture.host.innerHTML).toEqual('before|<!--ICU 20:0-->|after');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 0:0-->|after');
|
||||
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 20:0-->|after');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('x');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('before|otherCase<!--ICU 0:0-->|after');
|
||||
expect(fixture.host.innerHTML).toEqual('before|otherCase<!--ICU 20:0-->|after');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 0:0-->|after');
|
||||
expect(fixture.host.innerHTML).toEqual('before|caseA<!--ICU 20:0-->|after');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -122,23 +122,23 @@ describe('i18n_parse', () => {
|
|||
}`);
|
||||
fixture.apply(() => {
|
||||
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
|
||||
expect(fixture.host.innerHTML).toEqual('<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('<!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('x');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML)
|
||||
.toEqual('<div>nestedOther<!--nested ICU 0--></div><!--ICU 0:0-->');
|
||||
.toEqual('<div>nestedOther<!--nested ICU 0--></div><!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('Hello <b>world<i>!</i></b><!--ICU 20:0-->');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -154,7 +154,7 @@ describe('i18n_parse', () => {
|
|||
// 22: Binding for child ICU |
|
||||
// 23: Binding for child ICU |
|
||||
// ----- EXPANDO -----
|
||||
// 24: TIcu (parent) | <!-- ICU 0:0 -->
|
||||
// 24: TIcu (parent) | <!-- ICU 20:0 -->
|
||||
// 25: null | currently selected ICU case
|
||||
// 26: null | #text( parentA )
|
||||
// 27: TIcu (child) | <!-- nested ICU 0 -->
|
||||
|
@ -170,7 +170,7 @@ describe('i18n_parse', () => {
|
|||
}`);
|
||||
expect(tI18n).toEqual(matchTI18n({
|
||||
create: matchDebug([
|
||||
'lView[24] = document.createComment("ICU 0:0");',
|
||||
'lView[24] = document.createComment("ICU 20:0");',
|
||||
'parent.appendChild(lView[24]);',
|
||||
]),
|
||||
update: matchDebug([
|
||||
|
@ -244,45 +244,46 @@ describe('i18n_parse', () => {
|
|||
|
||||
fixture.apply(() => {
|
||||
applyCreateOpCodes(fixture.lView, tI18n.create, fixture.host, null);
|
||||
expect(fixture.host.innerHTML).toEqual('<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('<!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nExp('0');
|
||||
ɵɵi18nExp('value1');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('parentA nested0<!--nested ICU 0-->!<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML)
|
||||
.toEqual('parentA nested0<!--nested ICU 0-->!<!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nExp('x');
|
||||
ɵɵi18nExp('value1');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('parentA value1<!--nested ICU 0-->!<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('parentA value1<!--nested ICU 0-->!<!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('x');
|
||||
ɵɵi18nExp('x');
|
||||
ɵɵi18nExp('value2');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('parentOther<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('parentOther<!--ICU 20:0-->');
|
||||
});
|
||||
fixture.apply(() => {
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nExp('A');
|
||||
ɵɵi18nExp('value2');
|
||||
ɵɵi18nApply(0); // index 0 + HEADER_OFFSET = 20;
|
||||
expect(fixture.host.innerHTML).toEqual('parentA value2<!--nested ICU 0-->!<!--ICU 0:0-->');
|
||||
expect(fixture.host.innerHTML).toEqual('parentA value2<!--nested ICU 0-->!<!--ICU 20:0-->');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function toT18n(text: string) {
|
||||
const tNodeIndex = 0;
|
||||
const tNodeIndex = HEADER_OFFSET;
|
||||
fixture.enterView();
|
||||
i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, tNodeIndex, text, -1);
|
||||
fixture.leaveView();
|
||||
const tI18n = fixture.tView.data[tNodeIndex + HEADER_OFFSET] as TI18n;
|
||||
const tI18n = fixture.tView.data[tNodeIndex] as TI18n;
|
||||
expect(tI18n).toEqual(matchTI18n({}));
|
||||
return tI18n;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ describe('Runtime i18n', () => {
|
|||
const fixture = new TemplateFixture(
|
||||
{create: createTemplate, update: updateTemplate, decls: nbDecls, consts: [messageOrAtrs]});
|
||||
tView = fixture.hostView[TVIEW];
|
||||
return tView.data[index + HEADER_OFFSET] as TI18n;
|
||||
return tView.data[index] as TI18n | I18nUpdateOpCodes;
|
||||
}
|
||||
|
||||
describe('i18nStart', () => {
|
||||
|
@ -79,7 +79,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index) as TI18n;
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index) as TI18n;
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -100,7 +100,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -125,7 +125,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect((opCodes as any).update.debug).toEqual([
|
||||
'if (mask & 0b1) { (lView[22] as Text).textContent = `Hello ${lView[i-1]}!`; }'
|
||||
|
@ -150,7 +150,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -183,7 +183,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -205,7 +205,7 @@ describe('Runtime i18n', () => {
|
|||
opCodes = getOpCodes(message, () => {
|
||||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0, 1);
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, index + HEADER_OFFSET);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -223,7 +223,7 @@ describe('Runtime i18n', () => {
|
|||
opCodes = getOpCodes(message, () => {
|
||||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0, 2);
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, index + HEADER_OFFSET);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
|
@ -245,11 +245,11 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nStart(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index) as TI18n;
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index) as TI18n;
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 1:0");`,
|
||||
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 21:0");`,
|
||||
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
|
||||
]),
|
||||
update: matchDebug([
|
||||
|
@ -332,11 +332,11 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18n(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual({
|
||||
create: matchDebug([
|
||||
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 1:0");`,
|
||||
`lView[${HEADER_OFFSET + 2}] = document.createComment("ICU 21:0");`,
|
||||
`parent.appendChild(lView[${HEADER_OFFSET + 2}]);`,
|
||||
]),
|
||||
update: matchDebug([
|
||||
|
@ -432,11 +432,11 @@ describe('Runtime i18n', () => {
|
|||
consts: [attrs],
|
||||
});
|
||||
const tView = fixture.hostView[TVIEW];
|
||||
const opCodes = tView.data[index + HEADER_OFFSET] as I18nUpdateOpCodes;
|
||||
const opCodes = tView.data[HEADER_OFFSET + index] as I18nUpdateOpCodes;
|
||||
|
||||
expect(opCodes).toEqual([]);
|
||||
expect(
|
||||
(getNativeByIndex(0, fixture.hostView as LView) as any as Element).getAttribute('title'))
|
||||
expect((getNativeByIndex(HEADER_OFFSET, fixture.hostView as LView) as any as Element)
|
||||
.getAttribute('title'))
|
||||
.toEqual(message);
|
||||
});
|
||||
|
||||
|
@ -449,7 +449,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nAttributes(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual(matchDebug([
|
||||
'if (mask & 0b1) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }',
|
||||
|
@ -465,7 +465,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nAttributes(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual(matchDebug([
|
||||
'if (mask & 0b11) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]} and ${lView[i-2]}, again ${lView[i-1]}!`); }',
|
||||
|
@ -481,7 +481,7 @@ describe('Runtime i18n', () => {
|
|||
ɵɵelementStart(0, 'div');
|
||||
ɵɵi18nAttributes(index, 0);
|
||||
ɵɵelementEnd();
|
||||
}, undefined, nbConsts, index);
|
||||
}, undefined, nbConsts, HEADER_OFFSET + index);
|
||||
|
||||
expect(opCodes).toEqual(matchDebug([
|
||||
'if (mask & 0b1) { (lView[20] as Element).setAttribute(\'title\', `Hello ${lView[i-1]}!`); }',
|
||||
|
@ -631,14 +631,12 @@ describe('Runtime i18n', () => {
|
|||
|
||||
describe('i18nStartFirstCreatePass', () => {
|
||||
let fixture: ViewFixture;
|
||||
let divTNode: TElementNode;
|
||||
const DECLS = 20;
|
||||
const VARS = 10;
|
||||
beforeEach(() => {
|
||||
fixture = new ViewFixture({decls: DECLS, vars: VARS});
|
||||
fixture.enterView();
|
||||
ɵɵelementStart(0, 'div');
|
||||
divTNode = getCurrentTNode() as TElementNode;
|
||||
});
|
||||
|
||||
afterEach(ViewFixture.cleanUp);
|
||||
|
@ -661,7 +659,8 @@ describe('Runtime i18n', () => {
|
|||
}
|
||||
|
||||
it('should process text node with no siblings and no children', () => {
|
||||
i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello World!', -1);
|
||||
i18nStartFirstCreatePass(
|
||||
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello World!', -1);
|
||||
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
|
||||
// Expect that we only create the `Hello World!` text node and nothing else.
|
||||
expect(ti18n.create).toEqual([
|
||||
|
@ -672,7 +671,8 @@ describe('Runtime i18n', () => {
|
|||
});
|
||||
|
||||
it('should process text with a child node', () => {
|
||||
i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello <20>#2<><32>/#2<>!', -1);
|
||||
i18nStartFirstCreatePass(
|
||||
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello <20>#2<><32>/#2<>!', -1);
|
||||
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
|
||||
expect(ti18n.create).toEqual([
|
||||
i18nRangeOffsetOpcode(0), 'Hello ', //
|
||||
|
@ -689,7 +689,8 @@ describe('Runtime i18n', () => {
|
|||
});
|
||||
|
||||
it('should process text with a child node that has text', () => {
|
||||
i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello <20>#2<>World<6C>/#2<>!', -1);
|
||||
i18nStartFirstCreatePass(
|
||||
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello <20>#2<>World<6C>/#2<>!', -1);
|
||||
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
|
||||
expect(ti18n.create).toEqual([
|
||||
i18nRangeOffsetOpcode(0), 'Hello ', //
|
||||
|
@ -708,7 +709,7 @@ describe('Runtime i18n', () => {
|
|||
|
||||
it('should process text with a child node that has text and with bindings', () => {
|
||||
i18nStartFirstCreatePass(
|
||||
fixture.tView, 0, fixture.lView, 1,
|
||||
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1,
|
||||
'<27>0<EFBFBD> <20>#2<><32>1<EFBFBD><31>/#2<>!' /* {{salutation}} <b>{{name}}</b>! */, -1);
|
||||
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
|
||||
expect(ti18n.create).toEqual([
|
||||
|
@ -733,7 +734,8 @@ describe('Runtime i18n', () => {
|
|||
});
|
||||
|
||||
it('should process text with a child template', () => {
|
||||
i18nStartFirstCreatePass(fixture.tView, 0, fixture.lView, 1, 'Hello <20>*2:1<>World<6C>/*2:1<>!', -1);
|
||||
i18nStartFirstCreatePass(
|
||||
fixture.tView, 0, fixture.lView, HEADER_OFFSET + 1, 'Hello <20>*2:1<>World<6C>/*2:1<>!', -1);
|
||||
const ti18n = fixture.tView.data[HEADER_OFFSET + 1] as TI18n;
|
||||
expect(ti18n.create.debug).toEqual([
|
||||
'lView[50] = document.createText("Hello ");',
|
||||
|
|
|
@ -10,7 +10,7 @@ import {createLView, createTNode, createTView} from '@angular/core/src/render3/i
|
|||
import {TNodeType} from '@angular/core/src/render3/interfaces/node';
|
||||
import {domRendererFactory3} from '@angular/core/src/render3/interfaces/renderer';
|
||||
import {HEADER_OFFSET, LViewFlags, TVIEW, TViewType} from '@angular/core/src/render3/interfaces/view';
|
||||
import {enterView, getBindingRoot, getLView, setBindingIndex} from '@angular/core/src/render3/state';
|
||||
import {enterView, getBindingRoot, getLView, setBindingIndex, setSelectedIndex} from '@angular/core/src/render3/state';
|
||||
|
||||
|
||||
|
||||
|
@ -43,9 +43,10 @@ export function enterViewWithOneDiv() {
|
|||
const lView = createLView(
|
||||
null, tView, null, LViewFlags.CheckAlways, null, null, domRendererFactory3, renderer, null,
|
||||
null);
|
||||
lView[0 + HEADER_OFFSET] = div;
|
||||
tView.data[0 + HEADER_OFFSET] = tNode;
|
||||
lView[HEADER_OFFSET] = div;
|
||||
tView.data[HEADER_OFFSET] = tNode;
|
||||
enterView(lView);
|
||||
setSelectedIndex(HEADER_OFFSET);
|
||||
}
|
||||
|
||||
export function clearFirstUpdatePass() {
|
||||
|
|
|
@ -14,8 +14,6 @@ import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePre
|
|||
import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view';
|
||||
import {getLView, leaveView, setBindingRootForHostBindings} from '@angular/core/src/render3/state';
|
||||
import {getNativeByIndex} from '@angular/core/src/render3/util/view_utils';
|
||||
import {bypassSanitizationTrustStyle} from '@angular/core/src/sanitization/bypass';
|
||||
import {ɵɵsanitizeStyle} from '@angular/core/src/sanitization/sanitization';
|
||||
import {keyValueArraySet} from '@angular/core/src/util/array_utils';
|
||||
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
|
||||
import {getElementClasses, getElementStyles} from '@angular/core/testing/src/styling';
|
||||
|
@ -28,7 +26,7 @@ describe('styling', () => {
|
|||
afterEach(leaveView);
|
||||
|
||||
let div!: HTMLElement;
|
||||
beforeEach(() => div = getNativeByIndex(0, getLView()) as HTMLElement);
|
||||
beforeEach(() => div = getNativeByIndex(HEADER_OFFSET, getLView()) as HTMLElement);
|
||||
|
||||
it('should do set basic style', () => {
|
||||
ɵɵstyleProp('color', 'red');
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
||||
import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util';
|
||||
|
||||
import {ɵɵdefineComponent, ɵɵdefineDirective, ɵɵreference, ɵɵresolveBody, ɵɵresolveDocument} from '../../src/render3/index';
|
||||
import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵgetCurrentView, ɵɵlistener, ɵɵtext} from '../../src/render3/instructions/all';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
import {GlobalTargetResolver} from '../../src/render3/interfaces/renderer';
|
||||
import {ɵɵrestoreView} from '../../src/render3/state';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
import {ComponentFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, TemplateFixture} from './render_util';
|
||||
|
||||
|
@ -497,7 +496,7 @@ describe('event listeners', () => {
|
|||
}
|
||||
|
||||
// testing only
|
||||
compInstance = getDirectiveOnNode(0);
|
||||
compInstance = getDirectiveOnNode(HEADER_OFFSET);
|
||||
},
|
||||
directives: [Comp]
|
||||
});
|
||||
|
|
|
@ -56,7 +56,7 @@ describe('render3 matchers', () => {
|
|||
});
|
||||
describe('matchTNode', () => {
|
||||
const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null);
|
||||
const tNode = createTNode(tView, null, TNodeType.Element, 1, 'tagName', []);
|
||||
const tNode = createTNode(tView, null, TNodeType.Element, 0, 'tagName', []);
|
||||
|
||||
it('should match', () => {
|
||||
expect(tNode).toEqual(matchTNode());
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
|
||||
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
||||
|
||||
import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index';
|
||||
import {ɵɵdirectiveInject, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all';
|
||||
|
@ -72,8 +73,8 @@ describe('query', () => {
|
|||
ɵɵelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
child1 = getDirectiveOnNode(0);
|
||||
child2 = getDirectiveOnNode(1);
|
||||
child1 = getDirectiveOnNode(HEADER_OFFSET);
|
||||
child2 = getDirectiveOnNode(HEADER_OFFSET + 1);
|
||||
}
|
||||
},
|
||||
2, 0, [Child], [],
|
||||
|
@ -112,7 +113,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
}
|
||||
},
|
||||
1, 0, [Child], [],
|
||||
|
@ -150,7 +151,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementStart(0, 'div', 0);
|
||||
{ otherChildInstance = getDirectiveOnNode(0, 1); }
|
||||
{ otherChildInstance = getDirectiveOnNode(HEADER_OFFSET, 1); }
|
||||
ɵɵelementEnd();
|
||||
}
|
||||
},
|
||||
|
@ -345,7 +346,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', null, 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelement(2, 'div');
|
||||
}
|
||||
},
|
||||
|
@ -384,7 +385,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', null, 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelement(3, 'div');
|
||||
}
|
||||
},
|
||||
|
@ -431,10 +432,10 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', null, 0);
|
||||
el1ToQuery = getNativeByIndex(0, getLView());
|
||||
el1ToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelement(2, 'div');
|
||||
ɵɵelement(3, 'div', null, 1);
|
||||
el2ToQuery = getNativeByIndex(3, getLView());
|
||||
el2ToQuery = getNativeByIndex(HEADER_OFFSET + 3, getLView());
|
||||
}
|
||||
},
|
||||
5, 0, [], [],
|
||||
|
@ -471,7 +472,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', null, 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelement(2, 'div');
|
||||
}
|
||||
},
|
||||
|
@ -509,7 +510,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementContainerStart(0, null, 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelementContainerEnd();
|
||||
}
|
||||
},
|
||||
|
@ -546,7 +547,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelementContainerStart(0, null, 0);
|
||||
elToQuery = getNativeByIndex(0, getLView());
|
||||
elToQuery = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
ɵɵelementContainerEnd();
|
||||
}
|
||||
},
|
||||
|
@ -756,7 +757,7 @@ describe('query', () => {
|
|||
ɵɵelement(0, 'child', null, 0);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
childInstance = getDirectiveOnNode(0);
|
||||
childInstance = getDirectiveOnNode(HEADER_OFFSET);
|
||||
}
|
||||
},
|
||||
2, 0, [Child], [],
|
||||
|
@ -843,7 +844,7 @@ describe('query', () => {
|
|||
ɵɵelement(0, 'div', 0, 1);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
childInstance = getDirectiveOnNode(0);
|
||||
childInstance = getDirectiveOnNode(HEADER_OFFSET);
|
||||
}
|
||||
},
|
||||
2, 0, [Child], [],
|
||||
|
@ -883,8 +884,8 @@ describe('query', () => {
|
|||
ɵɵelement(0, 'div', 0, 1);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
child1Instance = getDirectiveOnNode(0, 0);
|
||||
child2Instance = getDirectiveOnNode(0, 1);
|
||||
child1Instance = getDirectiveOnNode(HEADER_OFFSET, 0);
|
||||
child2Instance = getDirectiveOnNode(HEADER_OFFSET, 1);
|
||||
}
|
||||
},
|
||||
3, 0, [Child1, Child2], [],
|
||||
|
@ -925,7 +926,7 @@ describe('query', () => {
|
|||
ɵɵelement(0, 'div', 0, 1);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
childInstance = getDirectiveOnNode(0);
|
||||
childInstance = getDirectiveOnNode(HEADER_OFFSET);
|
||||
}
|
||||
},
|
||||
3, 0, [Child], [],
|
||||
|
@ -970,7 +971,7 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', 0, 1);
|
||||
div = getNativeByIndex(0, getLView());
|
||||
div = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
}
|
||||
},
|
||||
2, 0, [Child], [],
|
||||
|
@ -1007,10 +1008,10 @@ describe('query', () => {
|
|||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ɵɵelement(0, 'div', 0, 1);
|
||||
div = getNativeByIndex(0, getLView());
|
||||
div = getNativeByIndex(HEADER_OFFSET, getLView());
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
childInstance = getDirectiveOnNode(0);
|
||||
childInstance = getDirectiveOnNode(HEADER_OFFSET);
|
||||
}
|
||||
},
|
||||
3, 0, [Child], [],
|
||||
|
@ -1570,8 +1571,8 @@ describe('query', () => {
|
|||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const lView = getLView();
|
||||
outInstance = load<QueryDirective>(lView, 1);
|
||||
inInstance = load<QueryDirective>(lView, 5);
|
||||
outInstance = load<QueryDirective>(lView, HEADER_OFFSET + 1);
|
||||
inInstance = load<QueryDirective>(lView, HEADER_OFFSET + 5);
|
||||
}
|
||||
},
|
||||
10, 0, [QueryDirective], [], null, [], [], undefined, [
|
||||
|
@ -1632,8 +1633,8 @@ describe('query', () => {
|
|||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const lView = getLView();
|
||||
outInstance = load<QueryDirective>(lView, 1);
|
||||
inInstance = load<QueryDirective>(lView, 3);
|
||||
outInstance = load<QueryDirective>(lView, HEADER_OFFSET + 1);
|
||||
inInstance = load<QueryDirective>(lView, HEADER_OFFSET + 3);
|
||||
}
|
||||
},
|
||||
7, 0, [QueryDirective], [], null, [], [], undefined, [
|
||||
|
@ -1692,8 +1693,8 @@ describe('query', () => {
|
|||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const lView = getLView();
|
||||
outInstance = load<QueryDirective>(lView, 1);
|
||||
inInstance = load<QueryDirective>(lView, 3);
|
||||
outInstance = load<QueryDirective>(lView, HEADER_OFFSET + 1);
|
||||
inInstance = load<QueryDirective>(lView, HEADER_OFFSET + 3);
|
||||
}
|
||||
},
|
||||
7, 0, [QueryDirective], [], null, [], [], undefined, [
|
||||
|
@ -1783,8 +1784,8 @@ describe('query', () => {
|
|||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
const lView = getLView();
|
||||
shallowInstance = load<ShallowQueryDirective>(lView, 1);
|
||||
deepInstance = load<DeepQueryDirective>(lView, 2);
|
||||
shallowInstance = load<ShallowQueryDirective>(lView, HEADER_OFFSET + 1);
|
||||
deepInstance = load<DeepQueryDirective>(lView, HEADER_OFFSET + 2);
|
||||
}
|
||||
},
|
||||
8, 0, [ShallowQueryDirective, DeepQueryDirective], [], null, [], [], undefined, [
|
||||
|
|
|
@ -17,7 +17,6 @@ import {TConstants, TNodeType} from '@angular/core/src/render3/interfaces/node';
|
|||
import {enterView, getLView} from '@angular/core/src/render3/state';
|
||||
import {EMPTY_ARRAY} from '@angular/core/src/util/empty';
|
||||
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
|
||||
|
||||
import {SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as R3_CHANGE_DETECTOR_REF_FACTORY} from '../../src/change_detection/change_detector_ref';
|
||||
import {Injector} from '../../src/di/injector';
|
||||
import {Type} from '../../src/interface/type';
|
||||
|
@ -33,11 +32,10 @@ import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveT
|
|||
import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
|
||||
import {PlayerHandler} from '../../src/render3/interfaces/player';
|
||||
import {domRendererFactory3, ProceduralRenderer3, RComment, RElement, Renderer3, RendererFactory3, RendererStyleFlags3, RNode, RText} from '../../src/render3/interfaces/renderer';
|
||||
import {HEADER_OFFSET, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../../src/render3/interfaces/view';
|
||||
import {HEADER_OFFSET, LView, LViewFlags, TVIEW, TViewType} from '../../src/render3/interfaces/view';
|
||||
import {destroyLView} from '../../src/render3/node_manipulation';
|
||||
import {getRootView} from '../../src/render3/util/view_traversal_utils';
|
||||
import {Sanitizer} from '../../src/sanitization/sanitizer';
|
||||
|
||||
import {getRendererFactory2} from './imported_renderer2';
|
||||
|
||||
|
||||
|
@ -434,7 +432,7 @@ export function createDirective(
|
|||
|
||||
/** Gets the directive on the given node at the given index */
|
||||
export function getDirectiveOnNode(nodeIndex: number, dirIndex: number = 0) {
|
||||
const directives = getDirectivesAtNodeIndex(nodeIndex + HEADER_OFFSET, getLView(), true);
|
||||
const directives = getDirectivesAtNodeIndex(nodeIndex, getLView(), true);
|
||||
if (directives == null) {
|
||||
throw new Error(`No directives exist on node in slot ${nodeIndex}`);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {HEADER_OFFSET} from '@angular/core/src/render3/interfaces/view';
|
||||
import {ChangeDetectorRef, Component as _Component, ComponentFactoryResolver, ElementRef, QueryList, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core';
|
||||
import {ViewEncapsulation} from '../../src/metadata';
|
||||
import {injectComponentFactoryResolver, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵlistener, ɵɵloadQuery, ɵɵqueryRefresh, ɵɵviewQuery} from '../../src/render3/index';
|
||||
|
@ -14,9 +15,9 @@ import {RenderFlags} from '../../src/render3/interfaces/definition';
|
|||
import {RElement} from '../../src/render3/interfaces/renderer';
|
||||
import {getLView} from '../../src/render3/state';
|
||||
import {getNativeByIndex} from '../../src/render3/util/view_utils';
|
||||
|
||||
import {ComponentFixture, createComponent, TemplateFixture} from './render_util';
|
||||
|
||||
|
||||
const Component: typeof _Component = function(...args: any[]): any {
|
||||
// In test we use @Component for documentation only so it's safe to mock out the implementation.
|
||||
return () => undefined;
|
||||
|
@ -362,7 +363,7 @@ describe('ViewContainerRef', () => {
|
|||
ɵɵelement(0, 'div', 1, 0);
|
||||
}
|
||||
// testing only
|
||||
fooEl = getNativeByIndex(0, getLView()) as RElement;
|
||||
fooEl = getNativeByIndex(HEADER_OFFSET, getLView()) as RElement;
|
||||
},
|
||||
viewQuery:
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
|
|
Loading…
Reference in New Issue