refactor(ivy): remove TStylingContext locking in favor of firstUpdatePass flag (#33521)
This patch removes the need to lock the style and class context instances to track when bindings can be added. What happens now is that the `tNode.firstUpdatePass` is used to track when bindings are registered on the context instances. PR Close #33521
This commit is contained in:
parent
5453c4cd96
commit
3297a76195
|
@ -13,14 +13,14 @@ import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../int
|
||||||
import {RElement} from '../interfaces/renderer';
|
import {RElement} from '../interfaces/renderer';
|
||||||
import {StylingMapArray, StylingMapArrayIndex, TStylingConfig, TStylingContext} from '../interfaces/styling';
|
import {StylingMapArray, StylingMapArrayIndex, TStylingConfig, TStylingContext} from '../interfaces/styling';
|
||||||
import {isDirectiveHost} from '../interfaces/type_checks';
|
import {isDirectiveHost} from '../interfaces/type_checks';
|
||||||
import {LView, RENDERER} from '../interfaces/view';
|
import {LView, RENDERER, TVIEW, TView} from '../interfaces/view';
|
||||||
import {getActiveDirectiveId, getCheckNoChangesMode, getCurrentStyleSanitizer, getLView, getSelectedIndex, incrementBindingIndex, nextBindingIndex, resetCurrentStyleSanitizer, setCurrentStyleSanitizer, setElementExitFn} from '../state';
|
import {getActiveDirectiveId, getCheckNoChangesMode, getCurrentStyleSanitizer, getLView, getSelectedIndex, incrementBindingIndex, nextBindingIndex, resetCurrentStyleSanitizer, setCurrentStyleSanitizer, setElementExitFn} from '../state';
|
||||||
import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, setClass, setStyle, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
|
import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, setClass, setStyle, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
|
||||||
import {activateStylingMapFeature} from '../styling/map_based_bindings';
|
import {activateStylingMapFeature} from '../styling/map_based_bindings';
|
||||||
import {attachStylingDebugObject} from '../styling/styling_debug';
|
import {attachStylingDebugObject} from '../styling/styling_debug';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {renderStringify} from '../util/misc_utils';
|
import {renderStringify} from '../util/misc_utils';
|
||||||
import {addItemToStylingMap, allocStylingMapArray, allocTStylingContext, allowDirectStyling, concatString, forceClassesAsString, forceStylesAsString, getInitialStylingValue, getStylingMapArray, getValue, hasClassInput, hasStyleInput, hasValueChanged, isContextLocked, isHostStylingActive, isStylingContext, normalizeIntoStylingMap, patchConfig, selectClassBasedInputName, setValue, stylingMapToString} from '../util/styling_utils';
|
import {addItemToStylingMap, allocStylingMapArray, allocTStylingContext, allowDirectStyling, concatString, forceClassesAsString, forceStylesAsString, getInitialStylingValue, getStylingMapArray, getValue, hasClassInput, hasStyleInput, hasValueChanged, isHostStylingActive, isStylingContext, isStylingValueDefined, normalizeIntoStylingMap, patchConfig, selectClassBasedInputName, setValue, stylingMapToString} from '../util/styling_utils';
|
||||||
import {getNativeByTNode, getTNode} from '../util/view_utils';
|
import {getNativeByTNode, getTNode} from '../util/view_utils';
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,17 +154,16 @@ function stylingProp(
|
||||||
let updated = false;
|
let updated = false;
|
||||||
|
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
|
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||||
const tNode = getTNode(elementIndex, lView);
|
const tNode = getTNode(elementIndex, lView);
|
||||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||||
|
|
||||||
const hostBindingsMode = isHostStyling();
|
|
||||||
const context = isClassBased ? getClassesContext(tNode) : getStylesContext(tNode);
|
const context = isClassBased ? getClassesContext(tNode) : getStylesContext(tNode);
|
||||||
const sanitizer = isClassBased ? null : getCurrentStyleSanitizer();
|
const sanitizer = isClassBased ? null : getCurrentStyleSanitizer();
|
||||||
|
|
||||||
// we check for this in the instruction code so that the context can be notified
|
// we check for this in the instruction code so that the context can be notified
|
||||||
// about prop or map bindings so that the direct apply check can decide earlier
|
// about prop or map bindings so that the direct apply check can decide earlier
|
||||||
// if it allows for context resolution to be bypassed.
|
// if it allows for context resolution to be bypassed.
|
||||||
if (!isContextLocked(context, hostBindingsMode)) {
|
if (firstUpdatePass) {
|
||||||
patchConfig(context, TStylingConfig.HasPropBindings);
|
patchConfig(context, TStylingConfig.HasPropBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +180,7 @@ function stylingProp(
|
||||||
|
|
||||||
// Direct Apply Case: bypass context resolution and apply the
|
// Direct Apply Case: bypass context resolution and apply the
|
||||||
// style/class value directly to the element
|
// style/class value directly to the element
|
||||||
if (allowDirectStyling(context, hostBindingsMode)) {
|
if (allowDirectStyling(context, firstUpdatePass)) {
|
||||||
const sanitizerToUse = isClassBased ? null : sanitizer;
|
const sanitizerToUse = isClassBased ? null : sanitizer;
|
||||||
const renderer = getRenderer(tNode, lView);
|
const renderer = getRenderer(tNode, lView);
|
||||||
updated = applyStylingValueDirectly(
|
updated = applyStylingValueDirectly(
|
||||||
|
@ -201,11 +200,11 @@ function stylingProp(
|
||||||
if (isClassBased) {
|
if (isClassBased) {
|
||||||
updated = updateClassViaContext(
|
updated = updateClassViaContext(
|
||||||
context, lView, native, directiveIndex, prop, bindingIndex,
|
context, lView, native, directiveIndex, prop, bindingIndex,
|
||||||
value as string | boolean | null);
|
value as string | boolean | null, false, firstUpdatePass);
|
||||||
} else {
|
} else {
|
||||||
updated = updateStyleViaContext(
|
updated = updateStyleViaContext(
|
||||||
context, lView, native, directiveIndex, prop, bindingIndex,
|
context, lView, native, directiveIndex, prop, bindingIndex,
|
||||||
value as string | SafeValue | null, sanitizer);
|
value as string | SafeValue | null, sanitizer, false, firstUpdatePass);
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementExitFn(stylingApply);
|
setElementExitFn(stylingApply);
|
||||||
|
@ -237,6 +236,7 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
|
||||||
const index = getSelectedIndex();
|
const index = getSelectedIndex();
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tNode = getTNode(index, lView);
|
const tNode = getTNode(index, lView);
|
||||||
|
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||||
const context = getStylesContext(tNode);
|
const context = getStylesContext(tNode);
|
||||||
const hasDirectiveInput = hasStyleInput(tNode);
|
const hasDirectiveInput = hasStyleInput(tNode);
|
||||||
|
|
||||||
|
@ -250,11 +250,12 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
|
||||||
// there should not be a situation where a directive host bindings function
|
// there should not be a situation where a directive host bindings function
|
||||||
// evaluates the inputs (this should only happen in the template function)
|
// evaluates the inputs (this should only happen in the template function)
|
||||||
if (!isHostStyling() && hasDirectiveInput && styles !== NO_CHANGE) {
|
if (!isHostStyling() && hasDirectiveInput && styles !== NO_CHANGE) {
|
||||||
updateDirectiveInputValue(context, lView, tNode, bindingIndex, styles, false);
|
updateDirectiveInputValue(context, lView, tNode, bindingIndex, styles, false, firstUpdatePass);
|
||||||
styles = NO_CHANGE;
|
styles = NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
stylingMap(context, tNode, lView, bindingIndex, styles, false, hasDirectiveInput);
|
stylingMap(
|
||||||
|
context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -289,6 +290,7 @@ export function classMapInternal(
|
||||||
elementIndex: number, classes: {[className: string]: any} | NO_CHANGE | string | null): void {
|
elementIndex: number, classes: {[className: string]: any} | NO_CHANGE | string | null): void {
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tNode = getTNode(elementIndex, lView);
|
const tNode = getTNode(elementIndex, lView);
|
||||||
|
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||||
const context = getClassesContext(tNode);
|
const context = getClassesContext(tNode);
|
||||||
const hasDirectiveInput = hasClassInput(tNode);
|
const hasDirectiveInput = hasClassInput(tNode);
|
||||||
|
|
||||||
|
@ -302,11 +304,12 @@ export function classMapInternal(
|
||||||
// there should not be a situation where a directive host bindings function
|
// there should not be a situation where a directive host bindings function
|
||||||
// evaluates the inputs (this should only happen in the template function)
|
// evaluates the inputs (this should only happen in the template function)
|
||||||
if (!isHostStyling() && hasDirectiveInput && classes !== NO_CHANGE) {
|
if (!isHostStyling() && hasDirectiveInput && classes !== NO_CHANGE) {
|
||||||
updateDirectiveInputValue(context, lView, tNode, bindingIndex, classes, true);
|
updateDirectiveInputValue(context, lView, tNode, bindingIndex, classes, true, firstUpdatePass);
|
||||||
classes = NO_CHANGE;
|
classes = NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
stylingMap(context, tNode, lView, bindingIndex, classes, true, hasDirectiveInput);
|
stylingMap(
|
||||||
|
context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,13 +319,12 @@ export function classMapInternal(
|
||||||
* `[class]` bindings in Angular.
|
* `[class]` bindings in Angular.
|
||||||
*/
|
*/
|
||||||
function stylingMap(
|
function stylingMap(
|
||||||
context: TStylingContext, tNode: TNode, lView: LView, bindingIndex: number,
|
context: TStylingContext, tNode: TNode, firstUpdatePass: boolean, lView: LView,
|
||||||
value: {[key: string]: any} | string | null, isClassBased: boolean,
|
bindingIndex: number, value: {[key: string]: any} | string | null, isClassBased: boolean,
|
||||||
hasDirectiveInput: boolean): void {
|
hasDirectiveInput: boolean): void {
|
||||||
const directiveIndex = getActiveDirectiveId();
|
const directiveIndex = getActiveDirectiveId();
|
||||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||||
const oldValue = getValue(lView, bindingIndex);
|
const oldValue = getValue(lView, bindingIndex);
|
||||||
const hostBindingsMode = isHostStyling();
|
|
||||||
const sanitizer = getCurrentStyleSanitizer();
|
const sanitizer = getCurrentStyleSanitizer();
|
||||||
const valueHasChanged = hasValueChanged(oldValue, value);
|
const valueHasChanged = hasValueChanged(oldValue, value);
|
||||||
|
|
||||||
|
@ -337,13 +339,13 @@ function stylingMap(
|
||||||
// we check for this in the instruction code so that the context can be notified
|
// we check for this in the instruction code so that the context can be notified
|
||||||
// about prop or map bindings so that the direct apply check can decide earlier
|
// about prop or map bindings so that the direct apply check can decide earlier
|
||||||
// if it allows for context resolution to be bypassed.
|
// if it allows for context resolution to be bypassed.
|
||||||
if (!isContextLocked(context, hostBindingsMode)) {
|
if (firstUpdatePass) {
|
||||||
patchConfig(context, TStylingConfig.HasMapBindings);
|
patchConfig(context, TStylingConfig.HasMapBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct Apply Case: bypass context resolution and apply the
|
// Direct Apply Case: bypass context resolution and apply the
|
||||||
// style/class map values directly to the element
|
// style/class map values directly to the element
|
||||||
if (allowDirectStyling(context, hostBindingsMode)) {
|
if (allowDirectStyling(context, firstUpdatePass)) {
|
||||||
const sanitizerToUse = isClassBased ? null : sanitizer;
|
const sanitizerToUse = isClassBased ? null : sanitizer;
|
||||||
const renderer = getRenderer(tNode, lView);
|
const renderer = getRenderer(tNode, lView);
|
||||||
applyStylingMapDirectly(
|
applyStylingMapDirectly(
|
||||||
|
@ -367,11 +369,11 @@ function stylingMap(
|
||||||
if (isClassBased) {
|
if (isClassBased) {
|
||||||
updateClassViaContext(
|
updateClassViaContext(
|
||||||
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr,
|
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr,
|
||||||
valueHasChanged);
|
valueHasChanged, firstUpdatePass);
|
||||||
} else {
|
} else {
|
||||||
updateStyleViaContext(
|
updateStyleViaContext(
|
||||||
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr, sanitizer,
|
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr, sanitizer,
|
||||||
valueHasChanged);
|
valueHasChanged, firstUpdatePass);
|
||||||
}
|
}
|
||||||
|
|
||||||
setElementExitFn(stylingApply);
|
setElementExitFn(stylingApply);
|
||||||
|
@ -396,18 +398,17 @@ function stylingMap(
|
||||||
* depending on the following situations:
|
* depending on the following situations:
|
||||||
*
|
*
|
||||||
* - If `oldValue !== newValue`
|
* - If `oldValue !== newValue`
|
||||||
* - If `newValue` is `null` (but this is skipped if it is during the first update pass--
|
* - If `newValue` is `null` (but this is skipped if it is during the first update pass)
|
||||||
* which is when the context is not locked yet)
|
|
||||||
*/
|
*/
|
||||||
function updateDirectiveInputValue(
|
function updateDirectiveInputValue(
|
||||||
context: TStylingContext, lView: LView, tNode: TNode, bindingIndex: number, newValue: any,
|
context: TStylingContext, lView: LView, tNode: TNode, bindingIndex: number, newValue: any,
|
||||||
isClassBased: boolean): void {
|
isClassBased: boolean, firstUpdatePass: boolean): void {
|
||||||
const oldValue = lView[bindingIndex];
|
const oldValue = getValue(lView, bindingIndex);
|
||||||
if (oldValue !== newValue) {
|
if (hasValueChanged(oldValue, newValue)) {
|
||||||
// even if the value has changed we may not want to emit it to the
|
// even if the value has changed we may not want to emit it to the
|
||||||
// directive input(s) in the event that it is falsy during the
|
// directive input(s) in the event that it is falsy during the
|
||||||
// first update pass.
|
// first update pass.
|
||||||
if (newValue || isContextLocked(context, false)) {
|
if (isStylingValueDefined(newValue) || !firstUpdatePass) {
|
||||||
const inputName: string = isClassBased ? selectClassBasedInputName(tNode.inputs !) : 'style';
|
const inputName: string = isClassBased ? selectClassBasedInputName(tNode.inputs !) : 'style';
|
||||||
const inputs = tNode.inputs ![inputName] !;
|
const inputs = tNode.inputs ![inputName] !;
|
||||||
const initialValue = getInitialStylingValue(context);
|
const initialValue = getInitialStylingValue(context);
|
||||||
|
@ -452,6 +453,7 @@ function normalizeStylingDirectiveInputValue(
|
||||||
*/
|
*/
|
||||||
function stylingApply(): void {
|
function stylingApply(): void {
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
|
const tView = lView[TVIEW];
|
||||||
const elementIndex = getSelectedIndex();
|
const elementIndex = getSelectedIndex();
|
||||||
const tNode = getTNode(elementIndex, lView);
|
const tNode = getTNode(elementIndex, lView);
|
||||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||||
|
@ -460,7 +462,9 @@ function stylingApply(): void {
|
||||||
const sanitizer = getCurrentStyleSanitizer();
|
const sanitizer = getCurrentStyleSanitizer();
|
||||||
const classesContext = isStylingContext(tNode.classes) ? tNode.classes as TStylingContext : null;
|
const classesContext = isStylingContext(tNode.classes) ? tNode.classes as TStylingContext : null;
|
||||||
const stylesContext = isStylingContext(tNode.styles) ? tNode.styles as TStylingContext : null;
|
const stylesContext = isStylingContext(tNode.styles) ? tNode.styles as TStylingContext : null;
|
||||||
flushStyling(renderer, lView, classesContext, stylesContext, native, directiveIndex, sanitizer);
|
flushStyling(
|
||||||
|
renderer, lView, classesContext, stylesContext, native, directiveIndex, sanitizer,
|
||||||
|
tView.firstUpdatePass);
|
||||||
resetCurrentStyleSanitizer();
|
resetCurrentStyleSanitizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ export const enum TStylingConfig {
|
||||||
/**
|
/**
|
||||||
* The initial state of the styling context config.
|
* The initial state of the styling context config.
|
||||||
*/
|
*/
|
||||||
Initial = 0b00000000,
|
Initial = 0b000000,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not there are any directives on this element.
|
* Whether or not there are any directives on this element.
|
||||||
|
@ -359,7 +359,7 @@ export const enum TStylingConfig {
|
||||||
* 3. `<comp>`
|
* 3. `<comp>`
|
||||||
* 4. `<comp dir-one>`
|
* 4. `<comp dir-one>`
|
||||||
*/
|
*/
|
||||||
HasDirectives = 0b00000001,
|
HasDirectives = 0b000001,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not there are prop-based bindings present.
|
* Whether or not there are prop-based bindings present.
|
||||||
|
@ -370,7 +370,7 @@ export const enum TStylingConfig {
|
||||||
* 3. `@HostBinding('style.prop') x`
|
* 3. `@HostBinding('style.prop') x`
|
||||||
* 4. `@HostBinding('class.prop') x`
|
* 4. `@HostBinding('class.prop') x`
|
||||||
*/
|
*/
|
||||||
HasPropBindings = 0b00000010,
|
HasPropBindings = 0b000010,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not there are map-based bindings present.
|
* Whether or not there are map-based bindings present.
|
||||||
|
@ -381,7 +381,7 @@ export const enum TStylingConfig {
|
||||||
* 3. `@HostBinding('style') x`
|
* 3. `@HostBinding('style') x`
|
||||||
* 4. `@HostBinding('class') x`
|
* 4. `@HostBinding('class') x`
|
||||||
*/
|
*/
|
||||||
HasMapBindings = 0b00000100,
|
HasMapBindings = 0b000100,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not there are map-based and prop-based bindings present.
|
* Whether or not there are map-based and prop-based bindings present.
|
||||||
|
@ -402,7 +402,7 @@ export const enum TStylingConfig {
|
||||||
* 2. map + prop: `<div [style]="x" [style.prop]>`
|
* 2. map + prop: `<div [style]="x" [style.prop]>`
|
||||||
* 3. map + map: `<div [style]="x" dir-that-sets-style>`
|
* 3. map + map: `<div [style]="x" dir-that-sets-style>`
|
||||||
*/
|
*/
|
||||||
HasCollisions = 0b00001000,
|
HasCollisions = 0b001000,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the context contains initial styling values.
|
* Whether or not the context contains initial styling values.
|
||||||
|
@ -413,7 +413,7 @@ export const enum TStylingConfig {
|
||||||
* 3. `@Directive({ host: { 'style': 'width:200px' } })`
|
* 3. `@Directive({ host: { 'style': 'width:200px' } })`
|
||||||
* 4. `@Directive({ host: { 'class': 'one two three' } })`
|
* 4. `@Directive({ host: { 'class': 'one two three' } })`
|
||||||
*/
|
*/
|
||||||
HasInitialStyling = 0b000010000,
|
HasInitialStyling = 0b0010000,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the context contains one or more template bindings.
|
* Whether or not the context contains one or more template bindings.
|
||||||
|
@ -424,7 +424,7 @@ export const enum TStylingConfig {
|
||||||
* 3. `<div [class]="x">`
|
* 3. `<div [class]="x">`
|
||||||
* 4. `<div [class.name]="x">`
|
* 4. `<div [class.name]="x">`
|
||||||
*/
|
*/
|
||||||
HasTemplateBindings = 0b000100000,
|
HasTemplateBindings = 0b0100000,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the context contains one or more host bindings.
|
* Whether or not the context contains one or more host bindings.
|
||||||
|
@ -435,35 +435,13 @@ export const enum TStylingConfig {
|
||||||
* 3. `@HostBinding('class') x`
|
* 3. `@HostBinding('class') x`
|
||||||
* 4. `@HostBinding('class.name') x`
|
* 4. `@HostBinding('class.name') x`
|
||||||
*/
|
*/
|
||||||
HasHostBindings = 0b001000000,
|
HasHostBindings = 0b1000000,
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the template bindings are allowed to be registered in the context.
|
|
||||||
*
|
|
||||||
* This flag is after one or more template-based style/class bindings were
|
|
||||||
* set and processed for an element. Once the bindings are processed then a call
|
|
||||||
* to stylingApply is issued and the lock will be put into place.
|
|
||||||
*
|
|
||||||
* Note that this is only set once.
|
|
||||||
*/
|
|
||||||
TemplateBindingsLocked = 0b010000000,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the host bindings are allowed to be registered in the context.
|
|
||||||
*
|
|
||||||
* This flag is after one or more host-based style/class bindings were
|
|
||||||
* set and processed for an element. Once the bindings are processed then a call
|
|
||||||
* to stylingApply is issued and the lock will be put into place.
|
|
||||||
*
|
|
||||||
* Note that this is only set once.
|
|
||||||
*/
|
|
||||||
HostBindingsLocked = 0b100000000,
|
|
||||||
|
|
||||||
/** A Mask of all the configurations */
|
/** A Mask of all the configurations */
|
||||||
Mask = 0b111111111,
|
Mask = 0b1111111,
|
||||||
|
|
||||||
/** Total amount of configuration bits used */
|
/** Total amount of configuration bits used */
|
||||||
TotalBits = 9,
|
TotalBits = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {global} from '../../util/global';
|
||||||
import {ProceduralRenderer3, RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
|
import {ProceduralRenderer3, RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
|
||||||
import {ApplyStylingFn, LStylingData, StylingMapArray, StylingMapArrayIndex, StylingMapsSyncMode, SyncStylingMapsFn, TStylingConfig, TStylingContext, TStylingContextIndex, TStylingContextPropConfigFlags} from '../interfaces/styling';
|
import {ApplyStylingFn, LStylingData, StylingMapArray, StylingMapArrayIndex, StylingMapsSyncMode, SyncStylingMapsFn, TStylingConfig, TStylingContext, TStylingContextIndex, TStylingContextPropConfigFlags} from '../interfaces/styling';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {DEFAULT_BINDING_INDEX, DEFAULT_BINDING_VALUE, DEFAULT_GUARD_MASK_VALUE, MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, concatString, forceStylesAsString, getBindingValue, getConfig, getDefaultValue, getGuardMask, getInitialStylingValue, getMapProp, getMapValue, getProp, getPropValuesStartPosition, getStylingMapArray, getTotalSources, getValue, getValuesCount, hasConfig, hasValueChanged, isContextLocked, isHostStylingActive, isSanitizationRequired, isStylingMapArray, isStylingValueDefined, lockContext, normalizeIntoStylingMap, patchConfig, setDefaultValue, setGuardMask, setMapAsDirty, setValue} from '../util/styling_utils';
|
import {DEFAULT_BINDING_INDEX, DEFAULT_BINDING_VALUE, DEFAULT_GUARD_MASK_VALUE, MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, concatString, forceStylesAsString, getBindingValue, getConfig, getDefaultValue, getGuardMask, getInitialStylingValue, getMapProp, getMapValue, getProp, getPropValuesStartPosition, getStylingMapArray, getTotalSources, getValue, getValuesCount, hasConfig, hasValueChanged, isHostStylingActive, isSanitizationRequired, isStylingMapArray, isStylingValueDefined, normalizeIntoStylingMap, patchConfig, setDefaultValue, setGuardMask, setMapAsDirty, setValue} from '../util/styling_utils';
|
||||||
|
|
||||||
import {getStylingState, resetStylingState} from './state';
|
import {getStylingState, resetStylingState} from './state';
|
||||||
|
|
||||||
|
@ -56,20 +56,19 @@ const STYLING_INDEX_FOR_MAP_BINDING = 0;
|
||||||
export function updateClassViaContext(
|
export function updateClassViaContext(
|
||||||
context: TStylingContext, data: LStylingData, element: RElement, directiveIndex: number,
|
context: TStylingContext, data: LStylingData, element: RElement, directiveIndex: number,
|
||||||
prop: string | null, bindingIndex: number,
|
prop: string | null, bindingIndex: number,
|
||||||
value: boolean | string | null | undefined | StylingMapArray | NO_CHANGE,
|
value: boolean | string | null | undefined | StylingMapArray | NO_CHANGE, forceUpdate: boolean,
|
||||||
forceUpdate?: boolean): boolean {
|
firstUpdatePass: boolean): boolean {
|
||||||
const isMapBased = !prop;
|
const isMapBased = !prop;
|
||||||
const state = getStylingState(element, directiveIndex);
|
const state = getStylingState(element, directiveIndex);
|
||||||
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.classesIndex++;
|
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.classesIndex++;
|
||||||
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
|
||||||
|
|
||||||
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngClass])
|
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngClass])
|
||||||
// then we still need to register the binding within the context so that the context
|
// then we still need to register the binding within the context so that the context
|
||||||
// is aware of the binding before it gets locked.
|
// is aware of the binding even if things change after the first update pass.
|
||||||
if (!isContextLocked(context, hostBindingsMode) || value !== NO_CHANGE) {
|
if (firstUpdatePass || value !== NO_CHANGE) {
|
||||||
const updated = updateBindingData(
|
const updated = updateBindingData(
|
||||||
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate,
|
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate, false,
|
||||||
false);
|
firstUpdatePass);
|
||||||
if (updated || forceUpdate) {
|
if (updated || forceUpdate) {
|
||||||
// We flip the bit in the bitMask to reflect that the binding
|
// We flip the bit in the bitMask to reflect that the binding
|
||||||
// at the `index` slot has changed. This identifies to the flushing
|
// at the `index` slot has changed. This identifies to the flushing
|
||||||
|
@ -97,22 +96,21 @@ export function updateStyleViaContext(
|
||||||
context: TStylingContext, data: LStylingData, element: RElement, directiveIndex: number,
|
context: TStylingContext, data: LStylingData, element: RElement, directiveIndex: number,
|
||||||
prop: string | null, bindingIndex: number,
|
prop: string | null, bindingIndex: number,
|
||||||
value: string | number | SafeValue | null | undefined | StylingMapArray | NO_CHANGE,
|
value: string | number | SafeValue | null | undefined | StylingMapArray | NO_CHANGE,
|
||||||
sanitizer: StyleSanitizeFn | null, forceUpdate?: boolean): boolean {
|
sanitizer: StyleSanitizeFn | null, forceUpdate: boolean, firstUpdatePass: boolean): boolean {
|
||||||
const isMapBased = !prop;
|
const isMapBased = !prop;
|
||||||
const state = getStylingState(element, directiveIndex);
|
const state = getStylingState(element, directiveIndex);
|
||||||
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;
|
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;
|
||||||
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
|
||||||
|
|
||||||
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngStyle])
|
// even if the initial value is a `NO_CHANGE` value (e.g. interpolation or [ngStyle])
|
||||||
// then we still need to register the binding within the context so that the context
|
// then we still need to register the binding within the context so that the context
|
||||||
// is aware of the binding before it gets locked.
|
// is aware of the binding even if things change after the first update pass.
|
||||||
if (!isContextLocked(context, hostBindingsMode) || value !== NO_CHANGE) {
|
if (firstUpdatePass || value !== NO_CHANGE) {
|
||||||
const sanitizationRequired = isMapBased ?
|
const sanitizationRequired = isMapBased ?
|
||||||
true :
|
true :
|
||||||
(sanitizer ? sanitizer(prop !, null, StyleSanitizeMode.ValidateProperty) : false);
|
(sanitizer ? sanitizer(prop !, null, StyleSanitizeMode.ValidateProperty) : false);
|
||||||
const updated = updateBindingData(
|
const updated = updateBindingData(
|
||||||
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate,
|
context, data, countIndex, state.sourceIndex, prop, bindingIndex, value, forceUpdate,
|
||||||
sanitizationRequired);
|
sanitizationRequired, firstUpdatePass);
|
||||||
if (updated || forceUpdate) {
|
if (updated || forceUpdate) {
|
||||||
// We flip the bit in the bitMask to reflect that the binding
|
// We flip the bit in the bitMask to reflect that the binding
|
||||||
// at the `index` slot has changed. This identifies to the flushing
|
// at the `index` slot has changed. This identifies to the flushing
|
||||||
|
@ -141,9 +139,9 @@ function updateBindingData(
|
||||||
context: TStylingContext, data: LStylingData, counterIndex: number, sourceIndex: number,
|
context: TStylingContext, data: LStylingData, counterIndex: number, sourceIndex: number,
|
||||||
prop: string | null, bindingIndex: number,
|
prop: string | null, bindingIndex: number,
|
||||||
value: string | SafeValue | number | boolean | null | undefined | StylingMapArray,
|
value: string | SafeValue | number | boolean | null | undefined | StylingMapArray,
|
||||||
forceUpdate?: boolean, sanitizationRequired?: boolean): boolean {
|
forceUpdate: boolean, sanitizationRequired: boolean, firstUpdatePass: boolean): boolean {
|
||||||
const hostBindingsMode = isHostStylingActive(sourceIndex);
|
const hostBindingsMode = isHostStylingActive(sourceIndex);
|
||||||
if (!isContextLocked(context, hostBindingsMode)) {
|
if (firstUpdatePass) {
|
||||||
// this will only happen during the first update pass of the
|
// this will only happen during the first update pass of the
|
||||||
// context. The reason why we can't use `tView.firstCreatePass`
|
// context. The reason why we can't use `tView.firstCreatePass`
|
||||||
// here is because its not guaranteed to be true when the first
|
// here is because its not guaranteed to be true when the first
|
||||||
|
@ -409,16 +407,16 @@ function addNewSourceColumn(context: TStylingContext): void {
|
||||||
export function flushStyling(
|
export function flushStyling(
|
||||||
renderer: Renderer3 | ProceduralRenderer3 | null, data: LStylingData,
|
renderer: Renderer3 | ProceduralRenderer3 | null, data: LStylingData,
|
||||||
classesContext: TStylingContext | null, stylesContext: TStylingContext | null,
|
classesContext: TStylingContext | null, stylesContext: TStylingContext | null,
|
||||||
element: RElement, directiveIndex: number, styleSanitizer: StyleSanitizeFn | null): void {
|
element: RElement, directiveIndex: number, styleSanitizer: StyleSanitizeFn | null,
|
||||||
|
firstUpdatePass: boolean): void {
|
||||||
ngDevMode && ngDevMode.flushStyling++;
|
ngDevMode && ngDevMode.flushStyling++;
|
||||||
|
|
||||||
const state = getStylingState(element, directiveIndex);
|
const state = getStylingState(element, directiveIndex);
|
||||||
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
const hostBindingsMode = isHostStylingActive(state.sourceIndex);
|
||||||
|
|
||||||
if (stylesContext) {
|
if (stylesContext) {
|
||||||
if (!isContextLocked(stylesContext, hostBindingsMode)) {
|
firstUpdatePass && syncContextInitialStyling(stylesContext);
|
||||||
lockAndFinalizeContext(stylesContext, hostBindingsMode);
|
|
||||||
}
|
|
||||||
if (state.stylesBitMask !== 0) {
|
if (state.stylesBitMask !== 0) {
|
||||||
applyStylingViaContext(
|
applyStylingViaContext(
|
||||||
stylesContext, renderer, element, data, state.stylesBitMask, setStyle, styleSanitizer,
|
stylesContext, renderer, element, data, state.stylesBitMask, setStyle, styleSanitizer,
|
||||||
|
@ -427,9 +425,8 @@ export function flushStyling(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classesContext) {
|
if (classesContext) {
|
||||||
if (!isContextLocked(classesContext, hostBindingsMode)) {
|
firstUpdatePass && syncContextInitialStyling(classesContext);
|
||||||
lockAndFinalizeContext(classesContext, hostBindingsMode);
|
|
||||||
}
|
|
||||||
if (state.classesBitMask !== 0) {
|
if (state.classesBitMask !== 0) {
|
||||||
applyStylingViaContext(
|
applyStylingViaContext(
|
||||||
classesContext, renderer, element, data, state.classesBitMask, setClass, null,
|
classesContext, renderer, element, data, state.classesBitMask, setClass, null,
|
||||||
|
@ -441,35 +438,64 @@ export function flushStyling(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locks the context (so no more bindings can be added) and also copies over initial class/style
|
* Registers all static styling values into the context as default values.
|
||||||
* values into their binding areas.
|
|
||||||
*
|
*
|
||||||
* There are two main actions that take place in this function:
|
* Static styles are stored on the `tNode.styles` and `tNode.classes`
|
||||||
|
* properties as instances of `StylingMapArray`. When an instance of
|
||||||
|
* `TStylingContext` is assigned to `tNode.styles` and `tNode.classes`
|
||||||
|
* then the existing initial styling values are copied into the the
|
||||||
|
* `InitialStylingValuePosition` slot.
|
||||||
*
|
*
|
||||||
* - Locking the context:
|
* Because all static styles/classes are collected and registered on
|
||||||
* Locking the context is required so that the style/class instructions know NOT to
|
* the initial styling array each time a directive is instantiated,
|
||||||
* register a binding again after the first update pass has run. If a locking bit was
|
* the context may not yet know about the static values. When this
|
||||||
* not used then it would need to scan over the context each time an instruction is run
|
* function is called it will copy over all the static style/class
|
||||||
* (which is expensive).
|
* values from the initial styling array into the context as default
|
||||||
|
* values for each of the matching entries in the context.
|
||||||
*
|
*
|
||||||
* - Patching initial values:
|
* Let's imagine the following example:
|
||||||
* Directives and component host bindings may include static class/style values which are
|
|
||||||
* bound to the host element. When this happens, the styling context will need to be informed
|
|
||||||
* so it can use these static styling values as defaults when a matching binding is falsy.
|
|
||||||
* These initial styling values are read from the initial styling values slot within the
|
|
||||||
* provided `TStylingContext` (which is an instance of a `StylingMapArray`). This inner map will
|
|
||||||
* be updated each time a host binding applies its static styling values (via `elementHostAttrs`)
|
|
||||||
* so these values are only read at this point because this is the very last point before the
|
|
||||||
* first style/class values are flushed to the element.
|
|
||||||
*
|
*
|
||||||
* Note that the `TStylingContext` styling context contains two locks: one for template bindings
|
* ```html
|
||||||
* and another for host bindings. Either one of these locks will be set when styling is applied
|
* <div style="color:red"
|
||||||
* during the template binding flush and/or during the host bindings flush.
|
* [style.color]="myColor"
|
||||||
|
* dir-that-has-static-height>
|
||||||
|
* ...
|
||||||
|
* </div>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* When the code above is processed, the underlying element/styling
|
||||||
|
* instructions will create an instance of `TStylingContext` for
|
||||||
|
* the `tNode.styles` property. Here's what that looks like:
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* tNode.styles = [
|
||||||
|
* // ...
|
||||||
|
* // initial styles
|
||||||
|
* ['color:red; height:200px', 'color', 'red', 'height', '200px'],
|
||||||
|
*
|
||||||
|
* 0, 0b1, 0b0, 'color', 20, null, // [style.color] binding
|
||||||
|
* ]
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* After this function is called it will balance out the context with
|
||||||
|
* the static `color` and `height` values and set them as defaults within
|
||||||
|
* the context:
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* tNode.styles = [
|
||||||
|
* // ...
|
||||||
|
* // initial styles
|
||||||
|
* ['color:red; height:200px', 'color', 'red', 'height', '200px'],
|
||||||
|
*
|
||||||
|
* 0, 0b1, 0b0, 'color', 20, 'red',
|
||||||
|
* 0, 0b0, 0b0, 'height', 0, '200px',
|
||||||
|
* ]
|
||||||
|
* ```
|
||||||
*/
|
*/
|
||||||
function lockAndFinalizeContext(context: TStylingContext, hostBindingsMode: boolean): void {
|
function syncContextInitialStyling(context: TStylingContext): void {
|
||||||
const initialValues = getStylingMapArray(context) !;
|
// the TStylingContext always has initial style/class values which are
|
||||||
updateInitialStylingOnContext(context, initialValues);
|
// stored in styling array format.
|
||||||
lockContext(context, hostBindingsMode);
|
updateInitialStylingOnContext(context, getStylingMapArray(context) !);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {RElement} from '../interfaces/renderer';
|
||||||
import {ApplyStylingFn, LStylingData, TStylingConfig, TStylingContext, TStylingContextIndex} from '../interfaces/styling';
|
import {ApplyStylingFn, LStylingData, TStylingConfig, TStylingContext, TStylingContextIndex} from '../interfaces/styling';
|
||||||
import {getCurrentStyleSanitizer} from '../state';
|
import {getCurrentStyleSanitizer} from '../state';
|
||||||
import {attachDebugObject} from '../util/debug_utils';
|
import {attachDebugObject} from '../util/debug_utils';
|
||||||
import {MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, allowDirectStyling as _allowDirectStyling, getBindingValue, getDefaultValue, getGuardMask, getProp, getPropValuesStartPosition, getValue, getValuesCount, hasConfig, isContextLocked, isSanitizationRequired, isStylingContext, normalizeIntoStylingMap, setValue} from '../util/styling_utils';
|
import {MAP_BASED_ENTRY_PROP_NAME, TEMPLATE_DIRECTIVE_INDEX, allowDirectStyling as _allowDirectStyling, getBindingValue, getDefaultValue, getGuardMask, getProp, getPropValuesStartPosition, getValue, getValuesCount, hasConfig, isSanitizationRequired, isStylingContext, normalizeIntoStylingMap, setValue} from '../util/styling_utils';
|
||||||
|
|
||||||
import {applyStylingViaContext} from './bindings';
|
import {applyStylingViaContext} from './bindings';
|
||||||
import {activateStylingMapFeature} from './map_based_bindings';
|
import {activateStylingMapFeature} from './map_based_bindings';
|
||||||
|
@ -55,14 +55,12 @@ export interface DebugStylingContext {
|
||||||
* A debug/testing-oriented summary of `TStylingConfig`.
|
* A debug/testing-oriented summary of `TStylingConfig`.
|
||||||
*/
|
*/
|
||||||
export interface DebugStylingConfig {
|
export interface DebugStylingConfig {
|
||||||
hasMapBindings: boolean; //
|
hasMapBindings: boolean; //
|
||||||
hasPropBindings: boolean; //
|
hasPropBindings: boolean; //
|
||||||
hasCollisions: boolean; //
|
hasCollisions: boolean; //
|
||||||
hasTemplateBindings: boolean; //
|
hasTemplateBindings: boolean; //
|
||||||
hasHostBindings: boolean; //
|
hasHostBindings: boolean; //
|
||||||
templateBindingsLocked: boolean; //
|
allowDirectStyling: boolean; //
|
||||||
hostBindingsLocked: boolean; //
|
|
||||||
allowDirectStyling: boolean; //
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -496,19 +494,17 @@ function buildConfig(context: TStylingContext) {
|
||||||
const hasCollisions = hasConfig(context, TStylingConfig.HasCollisions);
|
const hasCollisions = hasConfig(context, TStylingConfig.HasCollisions);
|
||||||
const hasTemplateBindings = hasConfig(context, TStylingConfig.HasTemplateBindings);
|
const hasTemplateBindings = hasConfig(context, TStylingConfig.HasTemplateBindings);
|
||||||
const hasHostBindings = hasConfig(context, TStylingConfig.HasHostBindings);
|
const hasHostBindings = hasConfig(context, TStylingConfig.HasHostBindings);
|
||||||
const templateBindingsLocked = hasConfig(context, TStylingConfig.TemplateBindingsLocked);
|
|
||||||
const hostBindingsLocked = hasConfig(context, TStylingConfig.HostBindingsLocked);
|
|
||||||
const allowDirectStyling =
|
|
||||||
_allowDirectStyling(context, false) || _allowDirectStyling(context, true);
|
|
||||||
|
|
||||||
|
// `firstTemplatePass` here is false because the context has already been constructed
|
||||||
|
// directly within the behavior of the debugging tools (outside of style/class debugging,
|
||||||
|
// the context is constructed during the first template pass).
|
||||||
|
const allowDirectStyling = _allowDirectStyling(context, false);
|
||||||
return {
|
return {
|
||||||
hasMapBindings, //
|
hasMapBindings, //
|
||||||
hasPropBindings, //
|
hasPropBindings, //
|
||||||
hasCollisions, //
|
hasCollisions, //
|
||||||
hasTemplateBindings, //
|
hasTemplateBindings, //
|
||||||
hasHostBindings, //
|
hasHostBindings, //
|
||||||
templateBindingsLocked, //
|
allowDirectStyling, //
|
||||||
hostBindingsLocked, //
|
|
||||||
allowDirectStyling, //
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,15 +74,16 @@ export function hasConfig(context: TStylingContext, flag: TStylingConfig) {
|
||||||
* Determines whether or not to apply styles/classes directly or via context resolution.
|
* Determines whether or not to apply styles/classes directly or via context resolution.
|
||||||
*
|
*
|
||||||
* There are three cases that are matched here:
|
* There are three cases that are matched here:
|
||||||
* 1. there are no directives present AND ngDevMode is falsy
|
* 1. there are no directives present AND `ngDevMode` is falsy
|
||||||
* 2. context is locked for template or host bindings (depending on `hostBindingsMode`)
|
* 2. the `firstUpdatePass` has not already run (which means that
|
||||||
|
* there are more bindings to register and, therefore, direct
|
||||||
|
* style/class application is not yet possible)
|
||||||
* 3. There are no collisions (i.e. properties with more than one binding) across multiple
|
* 3. There are no collisions (i.e. properties with more than one binding) across multiple
|
||||||
* sources (i.e. template + directive, directive + directive, directive + component)
|
* sources (i.e. template + directive, directive + directive, directive + component)
|
||||||
*/
|
*/
|
||||||
export function allowDirectStyling(context: TStylingContext, hostBindingsMode: boolean): boolean {
|
export function allowDirectStyling(context: TStylingContext, firstUpdatePass: boolean): boolean {
|
||||||
let allow = false;
|
let allow = false;
|
||||||
const config = getConfig(context);
|
const config = getConfig(context);
|
||||||
const contextIsLocked = (config & getLockedConfig(hostBindingsMode)) !== 0;
|
|
||||||
const hasNoDirectives = (config & TStylingConfig.HasDirectives) === 0;
|
const hasNoDirectives = (config & TStylingConfig.HasDirectives) === 0;
|
||||||
|
|
||||||
// if no directives are present then we do not need populate a context at all. This
|
// if no directives are present then we do not need populate a context at all. This
|
||||||
|
@ -93,8 +94,8 @@ export function allowDirectStyling(context: TStylingContext, hostBindingsMode: b
|
||||||
// `ngDevMode` is required to be checked here because tests/debugging rely on the context being
|
// `ngDevMode` is required to be checked here because tests/debugging rely on the context being
|
||||||
// populated. If things are in production mode then there is no need to build a context
|
// populated. If things are in production mode then there is no need to build a context
|
||||||
// therefore the direct apply can be allowed (even on the first update).
|
// therefore the direct apply can be allowed (even on the first update).
|
||||||
allow = ngDevMode ? contextIsLocked : true;
|
allow = ngDevMode ? !firstUpdatePass : true;
|
||||||
} else if (contextIsLocked) {
|
} else if (!firstUpdatePass) {
|
||||||
const hasNoCollisions = (config & TStylingConfig.HasCollisions) === 0;
|
const hasNoCollisions = (config & TStylingConfig.HasCollisions) === 0;
|
||||||
const hasOnlyMapsOrOnlyProps =
|
const hasOnlyMapsOrOnlyProps =
|
||||||
(config & TStylingConfig.HasPropAndMapBindings) !== TStylingConfig.HasPropAndMapBindings;
|
(config & TStylingConfig.HasPropAndMapBindings) !== TStylingConfig.HasPropAndMapBindings;
|
||||||
|
@ -172,19 +173,6 @@ export function getValue<T = any>(data: LStylingData, bindingIndex: number): T|n
|
||||||
return bindingIndex !== 0 ? data[bindingIndex] as T : null;
|
return bindingIndex !== 0 ? data[bindingIndex] as T : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lockContext(context: TStylingContext, hostBindingsMode: boolean): void {
|
|
||||||
patchConfig(context, getLockedConfig(hostBindingsMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isContextLocked(context: TStylingContext, hostBindingsMode: boolean): boolean {
|
|
||||||
return hasConfig(context, getLockedConfig(hostBindingsMode));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getLockedConfig(hostBindingsMode: boolean) {
|
|
||||||
return hostBindingsMode ? TStylingConfig.HostBindingsLocked :
|
|
||||||
TStylingConfig.TemplateBindingsLocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPropValuesStartPosition(context: TStylingContext) {
|
export function getPropValuesStartPosition(context: TStylingContext) {
|
||||||
let startPosition = TStylingContextIndex.ValuesStartPosition;
|
let startPosition = TStylingContextIndex.ValuesStartPosition;
|
||||||
if (hasConfig(context, TStylingConfig.HasMapBindings)) {
|
if (hasConfig(context, TStylingConfig.HasMapBindings)) {
|
||||||
|
|
|
@ -692,9 +692,6 @@
|
||||||
{
|
{
|
||||||
"name": "getLViewParent"
|
"name": "getLViewParent"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getLockedConfig"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getMapProp"
|
"name": "getMapProp"
|
||||||
},
|
},
|
||||||
|
@ -917,9 +914,6 @@
|
||||||
{
|
{
|
||||||
"name": "isContentQueryHost"
|
"name": "isContentQueryHost"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "isContextLocked"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "isCreationMode"
|
"name": "isCreationMode"
|
||||||
},
|
},
|
||||||
|
@ -938,9 +932,6 @@
|
||||||
{
|
{
|
||||||
"name": "isForwardRef"
|
"name": "isForwardRef"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "isHostStyling"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "isHostStylingActive"
|
"name": "isHostStylingActive"
|
||||||
},
|
},
|
||||||
|
@ -1007,12 +998,6 @@
|
||||||
{
|
{
|
||||||
"name": "locateHostElement"
|
"name": "locateHostElement"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "lockAndFinalizeContext"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "lockContext"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "looseIdentical"
|
"name": "looseIdentical"
|
||||||
},
|
},
|
||||||
|
@ -1292,6 +1277,9 @@
|
||||||
{
|
{
|
||||||
"name": "stylingProp"
|
"name": "stylingProp"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "syncContextInitialStyling"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "syncViewWithBlueprint"
|
"name": "syncViewWithBlueprint"
|
||||||
},
|
},
|
||||||
|
|
|
@ -170,21 +170,21 @@ describe('instructions', () => {
|
||||||
const detectedValues: string[] = [];
|
const detectedValues: string[] = [];
|
||||||
const sanitizerInterceptor =
|
const sanitizerInterceptor =
|
||||||
new MockSanitizerInterceptor(value => { detectedValues.push(value); });
|
new MockSanitizerInterceptor(value => { detectedValues.push(value); });
|
||||||
const fixture =
|
const fixture = new TemplateFixture(
|
||||||
createTemplateFixtureWithSanitizer(() => createDiv(), 1, sanitizerInterceptor);
|
() => { return createDiv(); }, //
|
||||||
|
() => {
|
||||||
fixture.update(() => {
|
ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer());
|
||||||
ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer());
|
ɵɵstyleMap({
|
||||||
ɵɵstyleMap({
|
'background-image': 'background-image',
|
||||||
'background-image': 'background-image',
|
'background': 'background',
|
||||||
'background': 'background',
|
'border-image': 'border-image',
|
||||||
'border-image': 'border-image',
|
'list-style': 'list-style',
|
||||||
'list-style': 'list-style',
|
'list-style-image': 'list-style-image',
|
||||||
'list-style-image': 'list-style-image',
|
'filter': 'filter',
|
||||||
'filter': 'filter',
|
'width': 'width'
|
||||||
'width': 'width'
|
});
|
||||||
});
|
},
|
||||||
});
|
1, 0, null, null, sanitizerInterceptor);
|
||||||
|
|
||||||
const props = detectedValues.sort();
|
const props = detectedValues.sort();
|
||||||
expect(props).toEqual([
|
expect(props).toEqual([
|
||||||
|
@ -197,8 +197,8 @@ describe('instructions', () => {
|
||||||
function createDivWithStyling() { ɵɵelement(0, 'div'); }
|
function createDivWithStyling() { ɵɵelement(0, 'div'); }
|
||||||
|
|
||||||
it('should add class', () => {
|
it('should add class', () => {
|
||||||
const fixture = new TemplateFixture(createDivWithStyling, () => {}, 1);
|
const fixture =
|
||||||
fixture.update(() => { ɵɵclassMap('multiple classes'); });
|
new TemplateFixture(createDivWithStyling, () => { ɵɵclassMap('multiple classes'); }, 1);
|
||||||
expect(fixture.html).toEqual('<div class="classes multiple"></div>');
|
expect(fixture.html).toEqual('<div class="classes multiple"></div>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -486,8 +486,3 @@ function stripStyleWsCharacters(value: string): string {
|
||||||
// color: blue; => color:blue
|
// color: blue; => color:blue
|
||||||
return value.replace(/;/g, '').replace(/:\s+/g, ':');
|
return value.replace(/;/g, '').replace(/:\s+/g, ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTemplateFixtureWithSanitizer(
|
|
||||||
buildFn: () => any, decls: number, sanitizer: Sanitizer) {
|
|
||||||
return new TemplateFixture(buildFn, () => {}, decls, 0, null, null, sanitizer);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue