refactor(ivy): move all styling configurations into TNodeFlags
(#33540)
This patch gets rid of the configuration settings present in the `TStylingContext` array that is used within the styling algorithm for `[style]`, `[style.prop]`, `[class]` and `[class.name]` bindings. These configurations now all live inside of the `TNodeFlags`. PR Close #33540
This commit is contained in:
@ -11,7 +11,7 @@ import {throwErrorIfNoChangesMode} from '../errors';
|
||||
import {setInputsForProperty} from '../instructions/shared';
|
||||
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {RElement} from '../interfaces/renderer';
|
||||
import {StylingMapArray, StylingMapArrayIndex, TStylingConfig, TStylingContext} from '../interfaces/styling';
|
||||
import {StylingMapArray, StylingMapArrayIndex, TStylingContext} from '../interfaces/styling';
|
||||
import {isDirectiveHost} from '../interfaces/type_checks';
|
||||
import {LView, RENDERER, TVIEW, TView} from '../interfaces/view';
|
||||
import {getActiveDirectiveId, getCheckNoChangesMode, getCurrentStyleSanitizer, getLView, getSelectedIndex, incrementBindingIndex, nextBindingIndex, resetCurrentStyleSanitizer, setCurrentStyleSanitizer, setElementExitFn} from '../state';
|
||||
@ -95,9 +95,21 @@ export function stylePropInternal(
|
||||
// still needs to be incremented because all styling binding values
|
||||
// are stored inside of the lView.
|
||||
const bindingIndex = nextBindingIndex();
|
||||
const lView = getLView();
|
||||
const tNode = getTNode(elementIndex, lView);
|
||||
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||
|
||||
const updated =
|
||||
stylingProp(elementIndex, bindingIndex, prop, resolveStylePropValue(value, suffix), false);
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(tNode, TNodeFlags.hasStylePropBindings);
|
||||
patchHostStylingFlag(tNode, isHostStyling(), false);
|
||||
}
|
||||
|
||||
const updated = stylingProp(
|
||||
tNode, firstUpdatePass, lView, bindingIndex, prop, resolveStylePropValue(value, suffix),
|
||||
false);
|
||||
if (ngDevMode) {
|
||||
ngDevMode.styleProp++;
|
||||
if (updated) {
|
||||
@ -127,8 +139,20 @@ export function ɵɵclassProp(className: string, value: boolean | null): void {
|
||||
// still needs to be incremented because all styling binding values
|
||||
// are stored inside of the lView.
|
||||
const bindingIndex = nextBindingIndex();
|
||||
const lView = getLView();
|
||||
const elementIndex = getSelectedIndex();
|
||||
const tNode = getTNode(elementIndex, lView);
|
||||
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||
|
||||
const updated = stylingProp(getSelectedIndex(), bindingIndex, className, value, true);
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(tNode, TNodeFlags.hasClassPropBindings);
|
||||
patchHostStylingFlag(tNode, isHostStyling(), true);
|
||||
}
|
||||
|
||||
const updated = stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true);
|
||||
if (ngDevMode) {
|
||||
ngDevMode.classProp++;
|
||||
if (updated) {
|
||||
@ -148,25 +172,15 @@ export function ɵɵclassProp(className: string, value: boolean | null): void {
|
||||
* present together).
|
||||
*/
|
||||
function stylingProp(
|
||||
elementIndex: number, bindingIndex: number, prop: string,
|
||||
tNode: TNode, firstUpdatePass: boolean, lView: LView, bindingIndex: number, prop: string,
|
||||
value: boolean | number | SafeValue | string | null | undefined | NO_CHANGE,
|
||||
isClassBased: boolean): boolean {
|
||||
let updated = false;
|
||||
|
||||
const lView = getLView();
|
||||
const firstUpdatePass = lView[TVIEW].firstUpdatePass;
|
||||
const tNode = getTNode(elementIndex, lView);
|
||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||
const context = isClassBased ? getClassesContext(tNode) : getStylesContext(tNode);
|
||||
const sanitizer = isClassBased ? null : getCurrentStyleSanitizer();
|
||||
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(context, TStylingConfig.HasPropBindings);
|
||||
}
|
||||
|
||||
// [style.prop] and [class.name] bindings do not use `bind()` and will
|
||||
// therefore manage accessing and updating the new value in the lView directly.
|
||||
// For this reason, the checkNoChanges situation must also be handled here
|
||||
@ -180,11 +194,12 @@ function stylingProp(
|
||||
|
||||
// Direct Apply Case: bypass context resolution and apply the
|
||||
// style/class value directly to the element
|
||||
if (allowDirectStyling(context, firstUpdatePass)) {
|
||||
if (allowDirectStyling(tNode, isClassBased, firstUpdatePass)) {
|
||||
const sanitizerToUse = isClassBased ? null : sanitizer;
|
||||
const renderer = getRenderer(tNode, lView);
|
||||
updated = applyStylingValueDirectly(
|
||||
renderer, context, native, lView, bindingIndex, prop, value, isClassBased, sanitizerToUse);
|
||||
renderer, context, tNode, native, lView, bindingIndex, prop, value, isClassBased,
|
||||
sanitizerToUse);
|
||||
|
||||
if (sanitizerToUse) {
|
||||
// it's important we remove the current style sanitizer once the
|
||||
@ -199,11 +214,11 @@ function stylingProp(
|
||||
const directiveIndex = getActiveDirectiveId();
|
||||
if (isClassBased) {
|
||||
updated = updateClassViaContext(
|
||||
context, lView, native, directiveIndex, prop, bindingIndex,
|
||||
context, tNode, lView, native, directiveIndex, prop, bindingIndex,
|
||||
value as string | boolean | null, false, firstUpdatePass);
|
||||
} else {
|
||||
updated = updateStyleViaContext(
|
||||
context, lView, native, directiveIndex, prop, bindingIndex,
|
||||
context, tNode, lView, native, directiveIndex, prop, bindingIndex,
|
||||
value as string | SafeValue | null, sanitizer, false, firstUpdatePass);
|
||||
}
|
||||
|
||||
@ -245,15 +260,24 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
|
||||
// still needs to be incremented because all styling binding values
|
||||
// are stored inside of the lView.
|
||||
const bindingIndex = incrementBindingIndex(2);
|
||||
const hostBindingsMode = isHostStyling();
|
||||
|
||||
// inputs are only evaluated from a template binding into a directive, therefore,
|
||||
// there should not be a situation where a directive host bindings function
|
||||
// evaluates the inputs (this should only happen in the template function)
|
||||
if (!isHostStyling() && hasDirectiveInput && styles !== NO_CHANGE) {
|
||||
if (!hostBindingsMode && hasDirectiveInput && styles !== NO_CHANGE) {
|
||||
updateDirectiveInputValue(context, lView, tNode, bindingIndex, styles, false, firstUpdatePass);
|
||||
styles = NO_CHANGE;
|
||||
}
|
||||
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(tNode, TNodeFlags.hasStyleMapBindings);
|
||||
patchHostStylingFlag(tNode, isHostStyling(), false);
|
||||
}
|
||||
|
||||
stylingMap(
|
||||
context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput);
|
||||
}
|
||||
@ -299,15 +323,24 @@ export function classMapInternal(
|
||||
// still needs to be incremented because all styling binding values
|
||||
// are stored inside of the lView.
|
||||
const bindingIndex = incrementBindingIndex(2);
|
||||
const hostBindingsMode = isHostStyling();
|
||||
|
||||
// inputs are only evaluated from a template binding into a directive, therefore,
|
||||
// there should not be a situation where a directive host bindings function
|
||||
// evaluates the inputs (this should only happen in the template function)
|
||||
if (!isHostStyling() && hasDirectiveInput && classes !== NO_CHANGE) {
|
||||
if (!hostBindingsMode && hasDirectiveInput && classes !== NO_CHANGE) {
|
||||
updateDirectiveInputValue(context, lView, tNode, bindingIndex, classes, true, firstUpdatePass);
|
||||
classes = NO_CHANGE;
|
||||
}
|
||||
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(tNode, TNodeFlags.hasClassMapBindings);
|
||||
patchHostStylingFlag(tNode, isHostStyling(), true);
|
||||
}
|
||||
|
||||
stylingMap(
|
||||
context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput);
|
||||
}
|
||||
@ -336,20 +369,13 @@ function stylingMap(
|
||||
throwErrorIfNoChangesMode(false, oldValue, value);
|
||||
}
|
||||
|
||||
// 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
|
||||
// if it allows for context resolution to be bypassed.
|
||||
if (firstUpdatePass) {
|
||||
patchConfig(context, TStylingConfig.HasMapBindings);
|
||||
}
|
||||
|
||||
// Direct Apply Case: bypass context resolution and apply the
|
||||
// style/class map values directly to the element
|
||||
if (allowDirectStyling(context, firstUpdatePass)) {
|
||||
if (allowDirectStyling(tNode, isClassBased, firstUpdatePass)) {
|
||||
const sanitizerToUse = isClassBased ? null : sanitizer;
|
||||
const renderer = getRenderer(tNode, lView);
|
||||
applyStylingMapDirectly(
|
||||
renderer, context, native, lView, bindingIndex, value, isClassBased, sanitizerToUse,
|
||||
renderer, context, tNode, native, lView, bindingIndex, value, isClassBased, sanitizerToUse,
|
||||
valueHasChanged, hasDirectiveInput);
|
||||
if (sanitizerToUse) {
|
||||
// it's important we remove the current style sanitizer once the
|
||||
@ -368,12 +394,12 @@ function stylingMap(
|
||||
// value to the element.
|
||||
if (isClassBased) {
|
||||
updateClassViaContext(
|
||||
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr,
|
||||
context, tNode, lView, native, directiveIndex, null, bindingIndex, stylingMapArr,
|
||||
valueHasChanged, firstUpdatePass);
|
||||
} else {
|
||||
updateStyleViaContext(
|
||||
context, lView, native, directiveIndex, null, bindingIndex, stylingMapArr, sanitizer,
|
||||
valueHasChanged, firstUpdatePass);
|
||||
context, tNode, lView, native, directiveIndex, null, bindingIndex, stylingMapArr,
|
||||
sanitizer, valueHasChanged, firstUpdatePass);
|
||||
}
|
||||
|
||||
setElementExitFn(stylingApply);
|
||||
@ -463,7 +489,7 @@ function stylingApply(): void {
|
||||
const classesContext = isStylingContext(tNode.classes) ? tNode.classes as TStylingContext : null;
|
||||
const stylesContext = isStylingContext(tNode.styles) ? tNode.styles as TStylingContext : null;
|
||||
flushStyling(
|
||||
renderer, lView, classesContext, stylesContext, native, directiveIndex, sanitizer,
|
||||
renderer, lView, tNode, classesContext, stylesContext, native, directiveIndex, sanitizer,
|
||||
tView.firstUpdatePass);
|
||||
resetCurrentStyleSanitizer();
|
||||
}
|
||||
@ -541,7 +567,7 @@ function getContext(tNode: TNode, isClassBased: boolean): TStylingContext {
|
||||
const hasDirectives = isDirectiveHost(tNode);
|
||||
context = allocTStylingContext(context as StylingMapArray | null, hasDirectives);
|
||||
if (ngDevMode) {
|
||||
attachStylingDebugObject(context as TStylingContext, isClassBased);
|
||||
attachStylingDebugObject(context as TStylingContext, tNode, isClassBased);
|
||||
}
|
||||
|
||||
if (isClassBased) {
|
||||
@ -582,3 +608,10 @@ function resolveStylePropValue(
|
||||
function isHostStyling(): boolean {
|
||||
return isHostStylingActive(getActiveDirectiveId());
|
||||
}
|
||||
|
||||
function patchHostStylingFlag(tNode: TNode, hostBindingsMode: boolean, isClassBased: boolean) {
|
||||
const flag = hostBindingsMode ?
|
||||
isClassBased ? TNodeFlags.hasHostClassBindings : TNodeFlags.hasHostStyleBindings :
|
||||
isClassBased ? TNodeFlags.hasTemplateClassBindings : TNodeFlags.hasTemplateStyleBindings;
|
||||
patchConfig(tNode, flag);
|
||||
}
|
||||
|
Reference in New Issue
Block a user