feat(ivy): add ΔpropertyInterpolate instructions (#29576)
- Adds the instructions - Adds tests for all instructions - Adds TODO to remove all tests when we are able to test this with TestBed after the compiler is updated PR Close #29576
This commit is contained in:
parent
b71cd7b4ee
commit
a80637e9a1
File diff suppressed because it is too large
Load Diff
@ -5,21 +5,14 @@
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '../../metadata/schema';
|
|
||||||
import {validateAgainstEventProperties} from '../../sanitization/sanitization';
|
|
||||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
|
|
||||||
import {assertLView} from '../assert';
|
|
||||||
import {bindingUpdated} from '../bindings';
|
import {bindingUpdated} from '../bindings';
|
||||||
import {PropertyAliasValue, PropertyAliases, TNode, TNodeType} from '../interfaces/node';
|
|
||||||
import {RComment, RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer';
|
|
||||||
import {SanitizerFn} from '../interfaces/sanitization';
|
import {SanitizerFn} from '../interfaces/sanitization';
|
||||||
import {BINDING_INDEX, FLAGS, HEADER_OFFSET, LView, LViewFlags, RENDERER, TData, TVIEW} from '../interfaces/view';
|
import {BINDING_INDEX} from '../interfaces/view';
|
||||||
import {getLView, getSelectedIndex} from '../state';
|
import {getLView, getSelectedIndex} from '../state';
|
||||||
import {ANIMATION_PROP_PREFIX, isAnimationProp} from '../styling/util';
|
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {INTERPOLATION_DELIMITER} from '../util/misc_utils';
|
|
||||||
import {getComponentViewByIndex, getNativeByIndex, getTNode, isComponent} from '../util/view_utils';
|
import {TsickleIssue1009, elementPropertyInternal, loadComponentRenderer, storeBindingMetadata} from './shared';
|
||||||
import {TsickleIssue1009, initializeTNodeInputs, loadComponentRenderer, setInputsForProperty, storeBindingMetadata} from './shared';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a property on a selected element.
|
* Update a property on a selected element.
|
||||||
@ -116,167 +109,3 @@ export function ΔcomponentHostSyntheticProperty<T>(
|
|||||||
nativeOnly?: boolean) {
|
nativeOnly?: boolean) {
|
||||||
elementPropertyInternal(index, propName, value, sanitizer, nativeOnly, loadComponentRenderer);
|
elementPropertyInternal(index, propName, value, sanitizer, nativeOnly, loadComponentRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping between attributes names that don't correspond to their element property names.
|
|
||||||
*/
|
|
||||||
const ATTR_TO_PROP: {[name: string]: string} = {
|
|
||||||
'class': 'className',
|
|
||||||
'for': 'htmlFor',
|
|
||||||
'formaction': 'formAction',
|
|
||||||
'innerHtml': 'innerHTML',
|
|
||||||
'readonly': 'readOnly',
|
|
||||||
'tabindex': 'tabIndex',
|
|
||||||
};
|
|
||||||
|
|
||||||
function elementPropertyInternal<T>(
|
|
||||||
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null,
|
|
||||||
nativeOnly?: boolean,
|
|
||||||
loadRendererFn?: ((tNode: TNode, lView: LView) => Renderer3) | null): void {
|
|
||||||
if (value === NO_CHANGE) return;
|
|
||||||
const lView = getLView();
|
|
||||||
const element = getNativeByIndex(index, lView) as RElement | RComment;
|
|
||||||
const tNode = getTNode(index, lView);
|
|
||||||
let inputData: PropertyAliases|null|undefined;
|
|
||||||
let dataValue: PropertyAliasValue|undefined;
|
|
||||||
if (!nativeOnly && (inputData = initializeTNodeInputs(tNode)) &&
|
|
||||||
(dataValue = inputData[propName])) {
|
|
||||||
setInputsForProperty(lView, dataValue, value);
|
|
||||||
if (isComponent(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET);
|
|
||||||
if (ngDevMode) {
|
|
||||||
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.Container) {
|
|
||||||
setNgReflectProperties(lView, element, tNode.type, dataValue, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (tNode.type === TNodeType.Element) {
|
|
||||||
propName = ATTR_TO_PROP[propName] || propName;
|
|
||||||
|
|
||||||
if (ngDevMode) {
|
|
||||||
validateAgainstEventProperties(propName);
|
|
||||||
validateAgainstUnknownProperties(lView, element, propName, tNode);
|
|
||||||
ngDevMode.rendererSetProperty++;
|
|
||||||
}
|
|
||||||
|
|
||||||
savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly);
|
|
||||||
|
|
||||||
const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER];
|
|
||||||
// It is assumed that the sanitizer is only added when the compiler determines that the property
|
|
||||||
// is risky, so sanitization can be done without further checks.
|
|
||||||
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
|
|
||||||
if (isProceduralRenderer(renderer)) {
|
|
||||||
renderer.setProperty(element as RElement, propName, value);
|
|
||||||
} else if (!isAnimationProp(propName)) {
|
|
||||||
(element as RElement).setProperty ? (element as any).setProperty(propName, value) :
|
|
||||||
(element as any)[propName] = value;
|
|
||||||
}
|
|
||||||
} else if (tNode.type === TNodeType.Container) {
|
|
||||||
// If the node is a container and the property didn't
|
|
||||||
// match any of the inputs or schemas we should throw.
|
|
||||||
if (ngDevMode && !matchingSchemas(lView, tNode.tagName)) {
|
|
||||||
throw createUnknownPropertyError(propName, tNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If node is an OnPush component, marks its LView dirty. */
|
|
||||||
function markDirtyIfOnPush(lView: LView, viewIndex: number): void {
|
|
||||||
ngDevMode && assertLView(lView);
|
|
||||||
const childComponentLView = getComponentViewByIndex(viewIndex, lView);
|
|
||||||
if (!(childComponentLView[FLAGS] & LViewFlags.CheckAlways)) {
|
|
||||||
childComponentLView[FLAGS] |= LViewFlags.Dirty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setNgReflectProperties(
|
|
||||||
lView: LView, element: RElement | RComment, type: TNodeType, inputs: PropertyAliasValue,
|
|
||||||
value: any) {
|
|
||||||
for (let i = 0; i < inputs.length; i += 3) {
|
|
||||||
const renderer = lView[RENDERER];
|
|
||||||
const attrName = normalizeDebugBindingName(inputs[i + 2] as string);
|
|
||||||
const debugValue = normalizeDebugBindingValue(value);
|
|
||||||
if (type === TNodeType.Element) {
|
|
||||||
isProceduralRenderer(renderer) ?
|
|
||||||
renderer.setAttribute((element as RElement), attrName, debugValue) :
|
|
||||||
(element as RElement).setAttribute(attrName, debugValue);
|
|
||||||
} else if (value !== undefined) {
|
|
||||||
const value = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
|
|
||||||
if (isProceduralRenderer(renderer)) {
|
|
||||||
renderer.setValue((element as RComment), value);
|
|
||||||
} else {
|
|
||||||
(element as RComment).textContent = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateAgainstUnknownProperties(
|
|
||||||
hostView: LView, element: RElement | RComment, propName: string, tNode: TNode) {
|
|
||||||
// If the tag matches any of the schemas we shouldn't throw.
|
|
||||||
if (matchingSchemas(hostView, tNode.tagName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If prop is not a known property of the HTML element...
|
|
||||||
if (!(propName in element) &&
|
|
||||||
// and we are in a browser context... (web worker nodes should be skipped)
|
|
||||||
typeof Node === 'function' && element instanceof Node &&
|
|
||||||
// and isn't a synthetic animation property...
|
|
||||||
propName[0] !== ANIMATION_PROP_PREFIX) {
|
|
||||||
// ... it is probably a user error and we should throw.
|
|
||||||
throw createUnknownPropertyError(propName, tNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function matchingSchemas(hostView: LView, tagName: string | null): boolean {
|
|
||||||
const schemas = hostView[TVIEW].schemas;
|
|
||||||
|
|
||||||
if (schemas !== null) {
|
|
||||||
for (let i = 0; i < schemas.length; i++) {
|
|
||||||
const schema = schemas[i];
|
|
||||||
if (schema === NO_ERRORS_SCHEMA ||
|
|
||||||
schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores debugging data for this property binding on first template pass.
|
|
||||||
* This enables features like DebugElement.properties.
|
|
||||||
*/
|
|
||||||
function savePropertyDebugData(
|
|
||||||
tNode: TNode, lView: LView, propName: string, tData: TData,
|
|
||||||
nativeOnly: boolean | undefined): void {
|
|
||||||
const lastBindingIndex = lView[BINDING_INDEX] - 1;
|
|
||||||
|
|
||||||
// Bind/interpolation functions save binding metadata in the last binding index,
|
|
||||||
// but leave the property name blank. If the interpolation delimiter is at the 0
|
|
||||||
// index, we know that this is our first pass and the property name still needs to
|
|
||||||
// be set.
|
|
||||||
const bindingMetadata = tData[lastBindingIndex] as string;
|
|
||||||
if (bindingMetadata[0] == INTERPOLATION_DELIMITER) {
|
|
||||||
tData[lastBindingIndex] = propName + bindingMetadata;
|
|
||||||
|
|
||||||
// We don't want to store indices for host bindings because they are stored in a
|
|
||||||
// different part of LView (the expando section).
|
|
||||||
if (!nativeOnly) {
|
|
||||||
if (tNode.propertyMetadataStartIndex == -1) {
|
|
||||||
tNode.propertyMetadataStartIndex = lastBindingIndex;
|
|
||||||
}
|
|
||||||
tNode.propertyMetadataEndIndex = lastBindingIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an error that should be thrown when encountering an unknown property on an element.
|
|
||||||
* @param propName Name of the invalid property.
|
|
||||||
* @param tNode Node on which we encountered the error.
|
|
||||||
*/
|
|
||||||
function createUnknownPropertyError(propName: string, tNode: TNode): Error {
|
|
||||||
return new Error(
|
|
||||||
`Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
|
|
||||||
}
|
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
import {assertEqual, assertLessThan} from '../../util/assert';
|
import {assertEqual, assertLessThan} from '../../util/assert';
|
||||||
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
|
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from '../bindings';
|
||||||
import {BINDING_INDEX, TVIEW} from '../interfaces/view';
|
import {BINDING_INDEX, TVIEW} from '../interfaces/view';
|
||||||
import {getLView} from '../state';
|
import {getLView, getSelectedIndex} from '../state';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {renderStringify} from '../util/misc_utils';
|
import {renderStringify} from '../util/misc_utils';
|
||||||
import {storeBindingMetadata} from './shared';
|
|
||||||
|
import {TsickleIssue1009, elementPropertyInternal, storeBindingMetadata} from './shared';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create interpolation bindings with a variable number of expressions.
|
* Create interpolation bindings with a variable number of expressions.
|
||||||
@ -283,3 +285,423 @@ export function Δinterpolation8(
|
|||||||
renderStringify(v6) + i6 + renderStringify(v7) + suffix :
|
renderStringify(v6) + i6 + renderStringify(v7) + suffix :
|
||||||
NO_CHANGE;
|
NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/// NEW INSTRUCTIONS
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared reference to a string, used in `ΔpropertyInterpolate`.
|
||||||
|
*/
|
||||||
|
const EMPTY_STRING = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with a lone bound value
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 1 interpolated value in it, an no additional text
|
||||||
|
* surrounds that interpolated value:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="{{v0}}"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate('title', v0);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate(propName: string, v0: any): TsickleIssue1009 {
|
||||||
|
ΔpropertyInterpolate1(propName, EMPTY_STRING, v0, EMPTY_STRING);
|
||||||
|
return ΔpropertyInterpolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with single bound value surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 1 interpolated value in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate1('title', 'prefix', v0, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate1(
|
||||||
|
propName: string, prefix: string, v0: any, suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(index, propName, Δinterpolation1(prefix, v0, suffix));
|
||||||
|
return ΔpropertyInterpolate1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 2 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 2 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate2('title', 'prefix', v0, '-', v1, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate2(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any,
|
||||||
|
suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(index, propName, Δinterpolation2(prefix, v0, i0, v1, suffix));
|
||||||
|
return ΔpropertyInterpolate2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 3 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 3 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate3(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate3(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any,
|
||||||
|
suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(index, propName, Δinterpolation3(prefix, v0, i0, v1, i1, v2, suffix));
|
||||||
|
return ΔpropertyInterpolate3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 4 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 4 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate4(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param i2 Static value used for concatenation only.
|
||||||
|
* @param v3 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate4(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||||
|
v3: any, suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(
|
||||||
|
index, propName, Δinterpolation4(prefix, v0, i0, v1, i1, v2, i2, v3, suffix));
|
||||||
|
return ΔpropertyInterpolate4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 5 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 5 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate5(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param i2 Static value used for concatenation only.
|
||||||
|
* @param v3 Value checked for change.
|
||||||
|
* @param i3 Static value used for concatenation only.
|
||||||
|
* @param v4 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate5(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||||
|
v3: any, i3: string, v4: any, suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(
|
||||||
|
index, propName, Δinterpolation5(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix));
|
||||||
|
return ΔpropertyInterpolate5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 6 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 6 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate6(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param i2 Static value used for concatenation only.
|
||||||
|
* @param v3 Value checked for change.
|
||||||
|
* @param i3 Static value used for concatenation only.
|
||||||
|
* @param v4 Value checked for change.
|
||||||
|
* @param i4 Static value used for concatenation only.
|
||||||
|
* @param v5 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate6(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||||
|
v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(
|
||||||
|
index, propName, Δinterpolation6(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix));
|
||||||
|
return ΔpropertyInterpolate6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 7 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 7 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate7(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param i2 Static value used for concatenation only.
|
||||||
|
* @param v3 Value checked for change.
|
||||||
|
* @param i3 Static value used for concatenation only.
|
||||||
|
* @param v4 Value checked for change.
|
||||||
|
* @param i4 Static value used for concatenation only.
|
||||||
|
* @param v5 Value checked for change.
|
||||||
|
* @param i5 Static value used for concatenation only.
|
||||||
|
* @param v6 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate7(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||||
|
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any,
|
||||||
|
suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(
|
||||||
|
index, propName,
|
||||||
|
Δinterpolation7(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix));
|
||||||
|
return ΔpropertyInterpolate7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update an interpolated property on an element with 8 bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the value passed to a property has 8 interpolated values in it:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolate8(
|
||||||
|
* 'title', 'prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, 'suffix');
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update
|
||||||
|
* @param prefix Static value used for concatenation only.
|
||||||
|
* @param v0 Value checked for change.
|
||||||
|
* @param i0 Static value used for concatenation only.
|
||||||
|
* @param v1 Value checked for change.
|
||||||
|
* @param i1 Static value used for concatenation only.
|
||||||
|
* @param v2 Value checked for change.
|
||||||
|
* @param i2 Static value used for concatenation only.
|
||||||
|
* @param v3 Value checked for change.
|
||||||
|
* @param i3 Static value used for concatenation only.
|
||||||
|
* @param v4 Value checked for change.
|
||||||
|
* @param i4 Static value used for concatenation only.
|
||||||
|
* @param v5 Value checked for change.
|
||||||
|
* @param i5 Static value used for concatenation only.
|
||||||
|
* @param v6 Value checked for change.
|
||||||
|
* @param i6 Static value used for concatenation only.
|
||||||
|
* @param v7 Value checked for change.
|
||||||
|
* @param suffix Static value used for concatenation only.
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolate8(
|
||||||
|
propName: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string,
|
||||||
|
v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
|
||||||
|
suffix: string): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
elementPropertyInternal(
|
||||||
|
index, propName,
|
||||||
|
Δinterpolation8(prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix));
|
||||||
|
return ΔpropertyInterpolate8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an interpolated property on an element with 8 or more bound values surrounded by text.
|
||||||
|
*
|
||||||
|
* Used when the number of interpolated values exceeds 7.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <div
|
||||||
|
* title="prefix{{v0}}-{{v1}}-{{v2}}-{{v3}}-{{v4}}-{{v5}}-{{v6}}-{{v7}}-{{v8}}-{{v9}}suffix"></div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Its compiled representation is::
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* ΔpropertyInterpolateV(
|
||||||
|
* 'title', ['prefix', v0, '-', v1, '-', v2, '-', v3, '-', v4, '-', v5, '-', v6, '-', v7, '-', v9,
|
||||||
|
* 'suffix']);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* If the property name also exists as an input property on one of the element's directives,
|
||||||
|
* the component property will be set instead of the element property. This check must
|
||||||
|
* be conducted at runtime so child components that add new `@Inputs` don't have to be re-compiled.
|
||||||
|
*
|
||||||
|
* @param propName The name of the property to update.
|
||||||
|
* @param values The a collection of values and the strings inbetween those values, beginning with a
|
||||||
|
* string prefix and ending with a string suffix.
|
||||||
|
* (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
|
||||||
|
* @returns itself, so that it may be chained.
|
||||||
|
*/
|
||||||
|
export function ΔpropertyInterpolateV(propName: string, values: any[]): TsickleIssue1009 {
|
||||||
|
const index = getSelectedIndex();
|
||||||
|
|
||||||
|
elementPropertyInternal(index, propName, ΔinterpolationV(values));
|
||||||
|
return ΔpropertyInterpolateV;
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import {HEADER_OFFSET, TVIEW} from '../interfaces/view';
|
|||||||
import {getCheckNoChangesMode, getLView, setSelectedIndex} from '../state';
|
import {getCheckNoChangesMode, getLView, setSelectedIndex} from '../state';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects an index of an item to act on and flushes lifecycle hooks up to this point
|
* Selects an element for later binding instructions.
|
||||||
*
|
*
|
||||||
* Used in conjunction with instructions like {@link property} to act on elements with specified
|
* Used in conjunction with instructions like {@link property} to act on elements with specified
|
||||||
* indices, for example those created with {@link element} or {@link elementStart}.
|
* indices, for example those created with {@link element} or {@link elementStart}.
|
||||||
|
@ -8,9 +8,11 @@
|
|||||||
import {Injector} from '../../di';
|
import {Injector} from '../../di';
|
||||||
import {ErrorHandler} from '../../error_handler';
|
import {ErrorHandler} from '../../error_handler';
|
||||||
import {Type} from '../../interface/type';
|
import {Type} from '../../interface/type';
|
||||||
import {SchemaMetadata} from '../../metadata/schema';
|
import {CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA, SchemaMetadata} from '../../metadata/schema';
|
||||||
|
import {validateAgainstEventProperties} from '../../sanitization/sanitization';
|
||||||
import {Sanitizer} from '../../sanitization/security';
|
import {Sanitizer} from '../../sanitization/security';
|
||||||
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertLessThan, assertNotEqual} from '../../util/assert';
|
import {assertDataInRange, assertDefined, assertDomNode, assertEqual, assertLessThan, assertNotEqual} from '../../util/assert';
|
||||||
|
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../../util/ng_reflect';
|
||||||
import {assertLView, assertPreviousIsParent} from '../assert';
|
import {assertLView, assertPreviousIsParent} from '../assert';
|
||||||
import {attachPatchData, getComponentViewByInstance} from '../context_discovery';
|
import {attachPatchData, getComponentViewByInstance} from '../context_discovery';
|
||||||
import {attachLContainerDebug, attachLViewDebug} from '../debug';
|
import {attachLContainerDebug, attachLViewDebug} from '../debug';
|
||||||
@ -23,17 +25,19 @@ import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/inj
|
|||||||
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node';
|
import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TContainerNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node';
|
||||||
import {LQueries} from '../interfaces/query';
|
import {LQueries} from '../interfaces/query';
|
||||||
import {RComment, RElement, RText, Renderer3, RendererFactory3, isProceduralRenderer} from '../interfaces/renderer';
|
import {RComment, RElement, RText, Renderer3, RendererFactory3, isProceduralRenderer} from '../interfaces/renderer';
|
||||||
|
import {SanitizerFn} from '../interfaces/sanitization';
|
||||||
import {StylingContext} from '../interfaces/styling';
|
import {StylingContext} from '../interfaces/styling';
|
||||||
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TVIEW, TView, T_HOST} from '../interfaces/view';
|
import {BINDING_INDEX, CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TData, TVIEW, TView, T_HOST} from '../interfaces/view';
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from '../node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from '../node_assert';
|
||||||
import {isNodeMatchingSelectorList} from '../node_selector_matcher';
|
import {isNodeMatchingSelectorList} from '../node_selector_matcher';
|
||||||
import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, incrementActiveDirectiveId, isCreationMode, leaveView, resetComponentState, setActiveHostElement, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode, setSelectedIndex, ΔnamespaceHTML} from '../state';
|
import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, incrementActiveDirectiveId, isCreationMode, leaveView, resetComponentState, setActiveHostElement, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode, setSelectedIndex, ΔnamespaceHTML} from '../state';
|
||||||
import {initializeStaticContext as initializeStaticStylingContext} from '../styling/class_and_style_bindings';
|
import {initializeStaticContext as initializeStaticStylingContext} from '../styling/class_and_style_bindings';
|
||||||
|
import {ANIMATION_PROP_PREFIX, isAnimationProp} from '../styling/util';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {attrsStylingIndexOf} from '../util/attrs_utils';
|
import {attrsStylingIndexOf} from '../util/attrs_utils';
|
||||||
import {INTERPOLATION_DELIMITER, renderStringify} from '../util/misc_utils';
|
import {INTERPOLATION_DELIMITER, renderStringify} from '../util/misc_utils';
|
||||||
import {getLViewParent, getRootContext} from '../util/view_traversal_utils';
|
import {getLViewParent, getRootContext} from '../util/view_traversal_utils';
|
||||||
import {getComponentViewByIndex, getNativeByTNode, isComponentDef, isContentQueryHost, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils';
|
import {getComponentViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isComponent, isComponentDef, isContentQueryHost, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -430,7 +434,7 @@ export function renderEmbeddedTemplate<T>(viewToRender: LView, tView: TView, con
|
|||||||
ΔnamespaceHTML();
|
ΔnamespaceHTML();
|
||||||
|
|
||||||
// Reset the selected index so we can assert that `select` was called later
|
// Reset the selected index so we can assert that `select` was called later
|
||||||
ngDevMode && setSelectedIndex(-1);
|
setSelectedIndex(-1);
|
||||||
|
|
||||||
tView.template !(getRenderFlags(viewToRender), context);
|
tView.template !(getRenderFlags(viewToRender), context);
|
||||||
// This must be set to false immediately after the first creation run because in an
|
// This must be set to false immediately after the first creation run because in an
|
||||||
@ -465,7 +469,7 @@ function renderComponentOrTemplate<T>(
|
|||||||
ΔnamespaceHTML();
|
ΔnamespaceHTML();
|
||||||
|
|
||||||
// Reset the selected index so we can assert that `select` was called later
|
// Reset the selected index so we can assert that `select` was called later
|
||||||
ngDevMode && setSelectedIndex(-1);
|
setSelectedIndex(-1);
|
||||||
|
|
||||||
templateFn(RenderFlags.Create, context);
|
templateFn(RenderFlags.Create, context);
|
||||||
}
|
}
|
||||||
@ -810,16 +814,169 @@ export function generatePropertyAliases(tNode: TNode, direction: BindingDirectio
|
|||||||
return propStore;
|
return propStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping between attributes names that don't correspond to their element property names.
|
||||||
|
*/
|
||||||
|
const ATTR_TO_PROP: {[name: string]: string} = {
|
||||||
|
'class': 'className',
|
||||||
|
'for': 'htmlFor',
|
||||||
|
'formaction': 'formAction',
|
||||||
|
'innerHtml': 'innerHTML',
|
||||||
|
'readonly': 'readOnly',
|
||||||
|
'tabindex': 'tabIndex',
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////
|
export function elementPropertyInternal<T>(
|
||||||
//// Text
|
index: number, propName: string, value: T | NO_CHANGE, sanitizer?: SanitizerFn | null,
|
||||||
//////////////////////////
|
nativeOnly?: boolean,
|
||||||
|
loadRendererFn?: ((tNode: TNode, lView: LView) => Renderer3) | null): void {
|
||||||
|
if (value === NO_CHANGE) return;
|
||||||
|
const lView = getLView();
|
||||||
|
const element = getNativeByIndex(index, lView) as RElement | RComment;
|
||||||
|
const tNode = getTNode(index, lView);
|
||||||
|
let inputData: PropertyAliases|null|undefined;
|
||||||
|
let dataValue: PropertyAliasValue|undefined;
|
||||||
|
if (!nativeOnly && (inputData = initializeTNodeInputs(tNode)) &&
|
||||||
|
(dataValue = inputData[propName])) {
|
||||||
|
setInputsForProperty(lView, dataValue, value);
|
||||||
|
if (isComponent(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET);
|
||||||
|
if (ngDevMode) {
|
||||||
|
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.Container) {
|
||||||
|
setNgReflectProperties(lView, element, tNode.type, dataValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (tNode.type === TNodeType.Element) {
|
||||||
|
propName = ATTR_TO_PROP[propName] || propName;
|
||||||
|
|
||||||
|
if (ngDevMode) {
|
||||||
|
validateAgainstEventProperties(propName);
|
||||||
|
validateAgainstUnknownProperties(lView, element, propName, tNode);
|
||||||
|
ngDevMode.rendererSetProperty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
savePropertyDebugData(tNode, lView, propName, lView[TVIEW].data, nativeOnly);
|
||||||
|
|
||||||
//////////////////////////
|
const renderer = loadRendererFn ? loadRendererFn(tNode, lView) : lView[RENDERER];
|
||||||
//// Directive
|
// It is assumed that the sanitizer is only added when the compiler determines that the property
|
||||||
//////////////////////////
|
// is risky, so sanitization can be done without further checks.
|
||||||
|
value = sanitizer != null ? (sanitizer(value, tNode.tagName || '', propName) as any) : value;
|
||||||
|
if (isProceduralRenderer(renderer)) {
|
||||||
|
renderer.setProperty(element as RElement, propName, value);
|
||||||
|
} else if (!isAnimationProp(propName)) {
|
||||||
|
(element as RElement).setProperty ? (element as any).setProperty(propName, value) :
|
||||||
|
(element as any)[propName] = value;
|
||||||
|
}
|
||||||
|
} else if (tNode.type === TNodeType.Container) {
|
||||||
|
// If the node is a container and the property didn't
|
||||||
|
// match any of the inputs or schemas we should throw.
|
||||||
|
if (ngDevMode && !matchingSchemas(lView, tNode.tagName)) {
|
||||||
|
throw createUnknownPropertyError(propName, tNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If node is an OnPush component, marks its LView dirty. */
|
||||||
|
function markDirtyIfOnPush(lView: LView, viewIndex: number): void {
|
||||||
|
ngDevMode && assertLView(lView);
|
||||||
|
const childComponentLView = getComponentViewByIndex(viewIndex, lView);
|
||||||
|
if (!(childComponentLView[FLAGS] & LViewFlags.CheckAlways)) {
|
||||||
|
childComponentLView[FLAGS] |= LViewFlags.Dirty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNgReflectProperties(
|
||||||
|
lView: LView, element: RElement | RComment, type: TNodeType, inputs: PropertyAliasValue,
|
||||||
|
value: any) {
|
||||||
|
for (let i = 0; i < inputs.length; i += 3) {
|
||||||
|
const renderer = lView[RENDERER];
|
||||||
|
const attrName = normalizeDebugBindingName(inputs[i + 2] as string);
|
||||||
|
const debugValue = normalizeDebugBindingValue(value);
|
||||||
|
if (type === TNodeType.Element) {
|
||||||
|
isProceduralRenderer(renderer) ?
|
||||||
|
renderer.setAttribute((element as RElement), attrName, debugValue) :
|
||||||
|
(element as RElement).setAttribute(attrName, debugValue);
|
||||||
|
} else if (value !== undefined) {
|
||||||
|
const value = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
|
||||||
|
if (isProceduralRenderer(renderer)) {
|
||||||
|
renderer.setValue((element as RComment), value);
|
||||||
|
} else {
|
||||||
|
(element as RComment).textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateAgainstUnknownProperties(
|
||||||
|
hostView: LView, element: RElement | RComment, propName: string, tNode: TNode) {
|
||||||
|
// If the tag matches any of the schemas we shouldn't throw.
|
||||||
|
if (matchingSchemas(hostView, tNode.tagName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If prop is not a known property of the HTML element...
|
||||||
|
if (!(propName in element) &&
|
||||||
|
// and we are in a browser context... (web worker nodes should be skipped)
|
||||||
|
typeof Node === 'function' && element instanceof Node &&
|
||||||
|
// and isn't a synthetic animation property...
|
||||||
|
propName[0] !== ANIMATION_PROP_PREFIX) {
|
||||||
|
// ... it is probably a user error and we should throw.
|
||||||
|
throw createUnknownPropertyError(propName, tNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchingSchemas(hostView: LView, tagName: string | null): boolean {
|
||||||
|
const schemas = hostView[TVIEW].schemas;
|
||||||
|
|
||||||
|
if (schemas !== null) {
|
||||||
|
for (let i = 0; i < schemas.length; i++) {
|
||||||
|
const schema = schemas[i];
|
||||||
|
if (schema === NO_ERRORS_SCHEMA ||
|
||||||
|
schema === CUSTOM_ELEMENTS_SCHEMA && tagName && tagName.indexOf('-') > -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores debugging data for this property binding on first template pass.
|
||||||
|
* This enables features like DebugElement.properties.
|
||||||
|
*/
|
||||||
|
function savePropertyDebugData(
|
||||||
|
tNode: TNode, lView: LView, propName: string, tData: TData,
|
||||||
|
nativeOnly: boolean | undefined): void {
|
||||||
|
const lastBindingIndex = lView[BINDING_INDEX] - 1;
|
||||||
|
|
||||||
|
// Bind/interpolation functions save binding metadata in the last binding index,
|
||||||
|
// but leave the property name blank. If the interpolation delimiter is at the 0
|
||||||
|
// index, we know that this is our first pass and the property name still needs to
|
||||||
|
// be set.
|
||||||
|
const bindingMetadata = tData[lastBindingIndex] as string;
|
||||||
|
if (bindingMetadata[0] == INTERPOLATION_DELIMITER) {
|
||||||
|
tData[lastBindingIndex] = propName + bindingMetadata;
|
||||||
|
|
||||||
|
// We don't want to store indices for host bindings because they are stored in a
|
||||||
|
// different part of LView (the expando section).
|
||||||
|
if (!nativeOnly) {
|
||||||
|
if (tNode.propertyMetadataStartIndex == -1) {
|
||||||
|
tNode.propertyMetadataStartIndex = lastBindingIndex;
|
||||||
|
}
|
||||||
|
tNode.propertyMetadataEndIndex = lastBindingIndex + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an error that should be thrown when encountering an unknown property on an element.
|
||||||
|
* @param propName Name of the invalid property.
|
||||||
|
* @param tNode Node on which we encountered the error.
|
||||||
|
*/
|
||||||
|
function createUnknownPropertyError(propName: string, tNode: TNode): Error {
|
||||||
|
return new Error(
|
||||||
|
`Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate a root component.
|
* Instantiate a root component.
|
||||||
@ -1515,7 +1672,7 @@ export function checkView<T>(hostView: LView, component: T) {
|
|||||||
creationMode && executeViewQueryFn(RenderFlags.Create, hostTView, component);
|
creationMode && executeViewQueryFn(RenderFlags.Create, hostTView, component);
|
||||||
|
|
||||||
// Reset the selected index so we can assert that `select` was called later
|
// Reset the selected index so we can assert that `select` was called later
|
||||||
ngDevMode && setSelectedIndex(-1);
|
setSelectedIndex(-1);
|
||||||
|
|
||||||
templateFn(getRenderFlags(hostView), component);
|
templateFn(getRenderFlags(hostView), component);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {NgForOfContext} from '@angular/common';
|
import {NgForOfContext} from '@angular/common';
|
||||||
|
import {ΔpropertyInterpolate, ΔpropertyInterpolate1, ΔpropertyInterpolate2, ΔpropertyInterpolate3, ΔpropertyInterpolate4, ΔpropertyInterpolate5, ΔpropertyInterpolate6, ΔpropertyInterpolate7, ΔpropertyInterpolate8, ΔpropertyInterpolateV} from '@angular/core/src/render3/instructions/all';
|
||||||
|
|
||||||
import {ΔdefineComponent} from '../../src/render3/definition';
|
import {ΔdefineComponent} from '../../src/render3/definition';
|
||||||
import {RenderFlags, Δbind, Δelement, ΔelementAttribute, ΔelementEnd, ΔelementProperty, ΔelementStart, ΔelementStyleProp, ΔelementStyling, ΔelementStylingApply, ΔelementStylingMap, Δinterpolation1, Δproperty, Δselect, Δtemplate, Δtext, ΔtextBinding} from '../../src/render3/index';
|
import {RenderFlags, Δbind, Δelement, ΔelementAttribute, ΔelementEnd, ΔelementProperty, ΔelementStart, ΔelementStyleProp, ΔelementStyling, ΔelementStylingApply, ΔelementStylingMap, Δinterpolation1, Δproperty, Δselect, Δtemplate, Δtext, ΔtextBinding} from '../../src/render3/index';
|
||||||
@ -161,7 +162,7 @@ describe('instructions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('select', () => {
|
describe('Δselect', () => {
|
||||||
it('should error in DevMode if index is out of range', () => {
|
it('should error in DevMode if index is out of range', () => {
|
||||||
// Only one constant added, meaning only index `0` is valid.
|
// Only one constant added, meaning only index `0` is valid.
|
||||||
const t = new TemplateFixture(createDiv, () => {}, 1, 0);
|
const t = new TemplateFixture(createDiv, () => {}, 1, 0);
|
||||||
@ -173,7 +174,7 @@ describe('instructions', () => {
|
|||||||
|
|
||||||
describe('property', () => {
|
describe('property', () => {
|
||||||
// TODO(benlesh): Replace with TestBed tests once the instruction is being generated.
|
// TODO(benlesh): Replace with TestBed tests once the instruction is being generated.
|
||||||
it('should set properties of the selected element', () => {
|
it('should set properties of the Δselected element', () => {
|
||||||
// <div [title]="title"></div>
|
// <div [title]="title"></div>
|
||||||
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
t.update(() => {
|
t.update(() => {
|
||||||
@ -241,7 +242,7 @@ describe('instructions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error in dev mode if select was not called prior', () => {
|
it('should error in dev mode if Δselect was not called prior', () => {
|
||||||
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
expect(() => { t.update(() => { Δproperty('title', 'test'); }); }).toThrow();
|
expect(() => { t.update(() => { Δproperty('title', 'test'); }); }).toThrow();
|
||||||
expect(() => {
|
expect(() => {
|
||||||
@ -253,6 +254,724 @@ describe('instructions', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
* TODO: REMOVE ALL OF THESE TemplateFixture TESTS FOR TestBed TESTS AFTER COMPILER IS UPDATED
|
||||||
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
*/
|
||||||
|
describe('ΔpropertyInterpolate instructions', () => {
|
||||||
|
describe('ΔpropertyInterpolate', () => {
|
||||||
|
it('should interpolate one value', () => {
|
||||||
|
// <div title="{{123}}"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate('title', 123);
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="123"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate('title', 'abc');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="abc"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="{{123}}" accesskey="{{'A'}}"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 2);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate('title', 123)('accessKey', 'A');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div accesskey="A" title="123"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate('title', 'abc')('accessKey', 'B');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div accesskey="B" title="abc"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
|
expect(() => { t.update(() => { ΔpropertyInterpolate('title', 123); }); }).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => { ΔpropertyInterpolate('title', 123); });
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate1', () => {
|
||||||
|
it('should interpolate one value', () => {
|
||||||
|
// <div title="start{{123}}end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate1('title', 'start', 123, 'end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start123end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate1('title', 'start', 'abc', 'end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="startabcend"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start{{123}}end" data-teststartstart{{'A'}}end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 2);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate1('title', 'start', 123, 'end')('accessKey', 'start', 'A', 'end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div accesskey="startAend" title="start123end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate1('title', 'start', 'abc', 'end')('accessKey', 'start', 'B', 'end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div accesskey="startBend" title="startabcend"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 1);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => { ΔpropertyInterpolate1('title', 'start', 'whatever', 'end'); });
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => { ΔpropertyInterpolate1('title', 'start', 'whatever', 'end'); });
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate2', () => {
|
||||||
|
it('should interpolate two values', () => {
|
||||||
|
// <div title="start: {{v0}}, 1: {{v1}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 2);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate2('title', 'start: ', 0, ', 1: ', 1, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: 0, 1: 1, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate2('title', 'start: ', 'A', ', 1: ', 'B', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: A, 1: B, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}}, end" accesskey="start: {{v0}}, 1: {{v1}},
|
||||||
|
// end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 4);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate2('title', 'start: ', 0, ', 1: ', 1, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, end" title="start: 0, 1: 1, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate2('title', 'start: ', 'A', ', 1: ', 'B', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, end" title="start: A, 1: B, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 2);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => { ΔpropertyInterpolate2('title', '', '', '', '', ''); });
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => { ΔpropertyInterpolate2('title', '', '', '', '', ''); });
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate3', () => {
|
||||||
|
it('should interpolate three values', () => {
|
||||||
|
// <div title="start: {{v0}}, 1: {{v1}}, 2: {{v2}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 3);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate3('title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: 0, 1: 1, 2: 2, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate3('title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: A, 1: B, 2: C, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}}, end" accesskey="start: {{v0}}, 1: {{v1}},
|
||||||
|
// 2: {{v2}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 6);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate3('title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, end" title="start: 0, 1: 1, 2: 2, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate3('title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, end" title="start: A, 1: B, 2: C, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 3);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => { ΔpropertyInterpolate3('title', '', '', '', '', '', '', ''); });
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => { ΔpropertyInterpolate3('title', '', '', '', '', '', '', ''); });
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate4', () => {
|
||||||
|
it('should interpolate four values', () => {
|
||||||
|
// <div title="start: {{v0}}, 1: {{v1}}, 2: {{v2}}, 3: {{v3}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 4);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate4('title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: 0, 1: 1, 2: 2, 3: 3, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate4(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: A, 1: B, 2: C, 3: D, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}}, end" accesskey="start: {{v0}} 1:
|
||||||
|
// {{v1}} 2: {{v2}} 3: {{v3}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 8);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate4('title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, end" title="start: 0, 1: 1, 2: 2, 3: 3, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate4(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, end" title="start: A, 1: B, 2: C, 3: D, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 4);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => { ΔpropertyInterpolate4('title', '', '', '', '', '', '', '', '', ''); });
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => { ΔpropertyInterpolate4('title', '', '', '', '', '', '', '', '', ''); });
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate5', () => {
|
||||||
|
it('should interpolate five values', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 5);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate5(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate5(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: A, 1: B, 2: C, 3: D, 4: E, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, end" accesskey="start:
|
||||||
|
// {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 10);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate5(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, end" title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate5(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, 4: E, end" title="start: A, 1: B, 2: C, 3: D, 4: E, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 5);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate5('title', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate5('title', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate6', () => {
|
||||||
|
it('should interpolate six values', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, 5: {{v5}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 6);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate6(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate6(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual('<div title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, 5: {{v5}}, end"
|
||||||
|
// accesskey="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}}, 5: {{v5}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 12);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate6(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, end" title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate6(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, end" title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 6);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate6('title', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate6('title', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate7', () => {
|
||||||
|
it('should interpolate seven values', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 7);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// 7: {{v7}} end" accesskey="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5:
|
||||||
|
// {{v5}}, 6: {{v6}}, end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 14);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, end" title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, end" title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 7);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate7(
|
||||||
|
'title', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolate8', () => {
|
||||||
|
it('should interpolate eight values', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// 7: {{v7}} end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 8);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', 7: ', 7, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', 7: ', 'H', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// 7: {{v7}} end" accesskey="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5:
|
||||||
|
// {{v5}}, 6: {{v6}}, 7: {{v7}} end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 16);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', 7: ', 7, ', end')(
|
||||||
|
'accessKey', 'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5,
|
||||||
|
', 6: ', 6, ', 7: ', 7, ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, end" title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', 7: ', 'H', ', end')(
|
||||||
|
'accessKey', 'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E',
|
||||||
|
', 5: ', 'F', ', 6: ', 'G', ', 7: ', 'H', ', end');
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, end" title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 8);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolate8(
|
||||||
|
'title', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('ΔpropertyInterpolateV', () => {
|
||||||
|
it('should interpolate eight or more values', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// 7: {{v7}}, 8: {{v8}} end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 9);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolateV('title', [
|
||||||
|
'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5, ', 6: ', 6,
|
||||||
|
', 7: ', 7, ', 8: ', 8, ', end'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolateV('title', [
|
||||||
|
'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E', ', 5: ', 'F',
|
||||||
|
', 6: ', 'G', ', 7: ', 'H', ', 8: ', 'I', ', end'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should chain', () => {
|
||||||
|
// <div title="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5: {{v5}}, 6: {{v6}},
|
||||||
|
// 7: {{v7}} end" accesskey="start: {{v0}} 1: {{v1}} 2: {{v2}} 3: {{v3}} 4: {{v4}} 5:
|
||||||
|
// {{v5}}, 6: {{v6}}, 7: {{v7}}, 8: {{v8}} end"></div>
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 18);
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolateV(
|
||||||
|
'title',
|
||||||
|
[
|
||||||
|
'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5, ', 6: ',
|
||||||
|
6, ', 7: ', 7, ', 8: ', 8, ', end'
|
||||||
|
])(
|
||||||
|
'accessKey', [
|
||||||
|
'start: ', 0, ', 1: ', 1, ', 2: ', 2, ', 3: ', 3, ', 4: ', 4, ', 5: ', 5, ', 6: ',
|
||||||
|
6, ', 7: ', 7, ', 8: ', 8, ', end'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, end" title="start: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, end"></div>');
|
||||||
|
t.update(() => {
|
||||||
|
Δselect(0);
|
||||||
|
ΔpropertyInterpolateV(
|
||||||
|
'title',
|
||||||
|
[
|
||||||
|
'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E', ', 5: ',
|
||||||
|
'F', ', 6: ', 'G', ', 7: ', 'H', ', 8: ', 'I', ', end'
|
||||||
|
])(
|
||||||
|
'accessKey', [
|
||||||
|
'start: ', 'A', ', 1: ', 'B', ', 2: ', 'C', ', 3: ', 'D', ', 4: ', 'E', ', 5: ',
|
||||||
|
'F', ', 6: ', 'G', ', 7: ', 'H', ', 8: ', 'I', ', end'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
expect(t.html).toEqual(
|
||||||
|
'<div accesskey="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, end" title="start: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, end"></div>');
|
||||||
|
expect(ngDevMode).toHaveProperties({
|
||||||
|
firstTemplatePass: 1,
|
||||||
|
tNode: 2, // 1 for div, 1 for host element
|
||||||
|
tView: 2, // 1 for rootView + 1 for the template view
|
||||||
|
rendererCreateElement: 1,
|
||||||
|
rendererSetProperty: 4,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if called without Δselect called first', () => {
|
||||||
|
const t = new TemplateFixture(createDiv, () => {}, 1, 9);
|
||||||
|
expect(() => {
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolateV(
|
||||||
|
'title',
|
||||||
|
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']);
|
||||||
|
});
|
||||||
|
}).toThrow();
|
||||||
|
expect(() => {
|
||||||
|
Δselect(0);
|
||||||
|
t.update(() => {
|
||||||
|
ΔpropertyInterpolateV(
|
||||||
|
'title',
|
||||||
|
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']);
|
||||||
|
});
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('elementProperty', () => {
|
describe('elementProperty', () => {
|
||||||
it('should use sanitizer function when available', () => {
|
it('should use sanitizer function when available', () => {
|
||||||
const t = new TemplateFixture(createDiv, () => {}, 1);
|
const t = new TemplateFixture(createDiv, () => {}, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user