fix(ivy): ensure parent/sub-class components evaluate styling correctly (#29602)
The new styling algorithm in angular is designed to evaluate host bindings stylinh priority in order of directive evaluation order. This, however, does not work with respect to parent/sub-class directives because sub-class host bindings are run after the parent host bindings but still have priority. This patch ensures that the host styling bindings for parent and sub-class components/directives are executed with respect to the styling algorithm prioritization. Jira Issue: FW-1132 PR Close #29602
This commit is contained in:
parent
5c13feebfd
commit
ec56354306
|
@ -12,7 +12,7 @@
|
|||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 1440,
|
||||
"main": 14106,
|
||||
"main": 14287,
|
||||
"polyfills": 43567
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import {PlayerHandler} from './interfaces/player';
|
|||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||
import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, RENDERER, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
|
||||
import {applyOnCreateInstructions} from './node_util';
|
||||
import {enterView, getPreviousOrParentTNode, leaveView, resetComponentState} from './state';
|
||||
import {enterView, getPreviousOrParentTNode, leaveView, resetComponentState, setActiveHostElement} from './state';
|
||||
import {renderInitialClasses, renderInitialStyles} from './styling/class_and_style_bindings';
|
||||
import {publishDefaultGlobalUtils} from './util/global_utils';
|
||||
import {defaultScheduler, renderStringify} from './util/misc_utils';
|
||||
|
@ -210,10 +210,15 @@ export function createRootComponent<T>(
|
|||
|
||||
const rootTNode = getPreviousOrParentTNode();
|
||||
if (tView.firstTemplatePass && componentDef.hostBindings) {
|
||||
const elementIndex = rootTNode.index - HEADER_OFFSET;
|
||||
setActiveHostElement(elementIndex);
|
||||
|
||||
const expando = tView.expandoInstructions !;
|
||||
invokeHostBindingsInCreationMode(
|
||||
componentDef, expando, component, rootTNode, tView.firstTemplatePass);
|
||||
rootTNode.onElementCreationFns && applyOnCreateInstructions(rootTNode);
|
||||
|
||||
setActiveHostElement(null);
|
||||
}
|
||||
|
||||
if (rootTNode.stylingTemplate) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import {Type} from '../../interface/type';
|
|||
import {fillProperties} from '../../util/property';
|
||||
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
||||
import {ComponentDef, DirectiveDef, DirectiveDefFeature, RenderFlags} from '../interfaces/definition';
|
||||
import {adjustActiveDirectiveSuperClassDepthPosition} from '../state';
|
||||
import {isComponentDef} from '../util/view_utils';
|
||||
|
||||
import {NgOnChangesFeature} from './ng_onchanges_feature';
|
||||
|
@ -63,8 +64,24 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
|
|||
const superHostBindings = superDef.hostBindings;
|
||||
if (superHostBindings) {
|
||||
if (prevHostBindings) {
|
||||
// because inheritance is unknown during compile time, the runtime code
|
||||
// needs to be informed of the super-class depth so that instruction code
|
||||
// can distinguish one host bindings function from another. The reason why
|
||||
// relying on the directive uniqueId exclusively is not enough is because the
|
||||
// uniqueId value and the directive instance stay the same between hostBindings
|
||||
// calls throughout the directive inheritance chain. This means that without
|
||||
// a super-class depth value, there is no way to know whether a parent or
|
||||
// sub-class host bindings function is currently being executed.
|
||||
definition.hostBindings = (rf: RenderFlags, ctx: any, elementIndex: number) => {
|
||||
superHostBindings(rf, ctx, elementIndex);
|
||||
// The reason why we increment first and then decrement is so that parent
|
||||
// hostBindings calls have a higher id value compared to sub-class hostBindings
|
||||
// calls (this way the leaf directive is always at a super-class depth of 0).
|
||||
adjustActiveDirectiveSuperClassDepthPosition(1);
|
||||
try {
|
||||
superHostBindings(rf, ctx, elementIndex);
|
||||
} finally {
|
||||
adjustActiveDirectiveSuperClassDepthPosition(-1);
|
||||
}
|
||||
prevHostBindings(rf, ctx, elementIndex);
|
||||
};
|
||||
} else {
|
||||
|
|
|
@ -11,20 +11,23 @@ import {assertHasParent} from '../assert';
|
|||
import {attachPatchData} from '../context_discovery';
|
||||
import {registerPostOrderHooks} from '../hooks';
|
||||
import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer';
|
||||
import {RElement, isProceduralRenderer} from '../interfaces/renderer';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view';
|
||||
import {assertNodeType} from '../node_assert';
|
||||
import {appendChild} from '../node_manipulation';
|
||||
import {applyOnCreateInstructions} from '../node_util';
|
||||
import {decreaseElementDepthCount, getActiveHostContext, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, increaseElementDepthCount, setIsParent, setPreviousOrParentTNode} from '../state';
|
||||
import {decreaseElementDepthCount, getActiveDirectiveId, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getSelectedIndex, increaseElementDepthCount, setIsParent, setPreviousOrParentTNode} from '../state';
|
||||
import {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles} from '../styling/class_and_style_bindings';
|
||||
import {getStylingContext, hasClassInput, hasStyleInput} from '../styling/util';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils';
|
||||
import {renderStringify} from '../util/misc_utils';
|
||||
import {getNativeByIndex, getNativeByTNode, getTNode} from '../util/view_utils';
|
||||
|
||||
import {createDirectivesAndLocals, createNodeAtIndex, elementCreate, executeContentQueries, initializeTNodeInputs, setInputsForProperty, setNodeStylingTemplate} from './shared';
|
||||
import {getActiveDirectiveStylingIndex} from './styling_instructions';
|
||||
|
||||
|
||||
/**
|
||||
* Create DOM element. The instruction must later be followed by `elementEnd()` call.
|
||||
|
@ -256,17 +259,26 @@ export function elementAttribute(
|
|||
* @publicApi
|
||||
*/
|
||||
export function elementHostAttrs(attrs: TAttributes) {
|
||||
const tNode = getPreviousOrParentTNode();
|
||||
const hostElementIndex = getSelectedIndex();
|
||||
const lView = getLView();
|
||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||
const lastAttrIndex = setUpAttributes(native, attrs);
|
||||
const stylingAttrsStartIndex = attrsStylingIndexOf(attrs, lastAttrIndex);
|
||||
if (stylingAttrsStartIndex >= 0) {
|
||||
const directive = getActiveHostContext();
|
||||
if (tNode.stylingTemplate) {
|
||||
patchContextWithStaticAttrs(tNode.stylingTemplate, attrs, stylingAttrsStartIndex, directive);
|
||||
} else {
|
||||
tNode.stylingTemplate = initializeStaticContext(attrs, stylingAttrsStartIndex, directive);
|
||||
const tNode = getTNode(hostElementIndex, lView);
|
||||
|
||||
// non-element nodes (e.g. `<ng-container>`) are not rendered as actual
|
||||
// element nodes and adding styles/classes on to them will cause runtime
|
||||
// errors...
|
||||
if (tNode.type === TNodeType.Element) {
|
||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||
const lastAttrIndex = setUpAttributes(native, attrs);
|
||||
const stylingAttrsStartIndex = attrsStylingIndexOf(attrs, lastAttrIndex);
|
||||
if (stylingAttrsStartIndex >= 0) {
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
if (tNode.stylingTemplate) {
|
||||
patchContextWithStaticAttrs(
|
||||
tNode.stylingTemplate, attrs, stylingAttrsStartIndex, directiveStylingIndex);
|
||||
} else {
|
||||
tNode.stylingTemplate =
|
||||
initializeStaticContext(attrs, stylingAttrsStartIndex, directiveStylingIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {TAttributes, TNodeType} from '../interfaces/node';
|
|||
import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view';
|
||||
import {assertNodeType} from '../node_assert';
|
||||
import {appendChild} from '../node_manipulation';
|
||||
import {applyOnCreateInstructions} from '../node_util';
|
||||
import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from '../state';
|
||||
import {createDirectivesAndLocals, createNodeAtIndex, executeContentQueries, setNodeStylingTemplate} from './shared';
|
||||
|
||||
|
@ -83,5 +84,9 @@ export function elementContainerEnd(): void {
|
|||
lView[QUERIES] = currentQueries.parent;
|
||||
}
|
||||
|
||||
// this is required for all host-level styling-related instructions to run
|
||||
// in the correct order
|
||||
previousOrParentTNode.onElementCreationFns && applyOnCreateInstructions(previousOrParentTNode);
|
||||
|
||||
registerPostOrderHooks(tView, previousOrParentTNode);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ 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 {assertNodeOfPossibleTypes, assertNodeType} from '../node_assert';
|
||||
import {isNodeMatchingSelectorList} from '../node_selector_matcher';
|
||||
import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, isCreationMode, leaveView, namespaceHTML, resetComponentState, setActiveHost, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode, setSelectedIndex} from '../state';
|
||||
import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, incrementActiveDirectiveId, isCreationMode, leaveView, namespaceHTML, resetComponentState, setActiveHostElement, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setIsParent, setPreviousOrParentTNode, setSelectedIndex} from '../state';
|
||||
import {initializeStaticContext as initializeStaticStylingContext} from '../styling/class_and_style_bindings';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {attrsStylingIndexOf} from '../util/attrs_utils';
|
||||
|
@ -35,6 +35,7 @@ import {INTERPOLATION_DELIMITER, renderStringify} from '../util/misc_utils';
|
|||
import {getLViewParent, getRootContext} from '../util/view_traversal_utils';
|
||||
import {getComponentViewByIndex, getNativeByTNode, isComponentDef, isContentQueryHost, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_utils';
|
||||
|
||||
|
||||
/**
|
||||
* A permanent marker promise which signifies that the current CD tree is
|
||||
* clean.
|
||||
|
@ -107,6 +108,8 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
|||
// Negative numbers mean that we are starting new EXPANDO block and need to update
|
||||
// the current element and directive index.
|
||||
currentElementIndex = -instruction;
|
||||
setActiveHostElement(currentElementIndex);
|
||||
|
||||
// Injector block and providers are taken into account.
|
||||
const providerCount = (tView.expandoInstructions[++i] as number);
|
||||
bindingRootIndex += INJECTOR_BLOOM_PARENT_SIZE + providerCount;
|
||||
|
@ -124,14 +127,20 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
|||
if (instruction !== null) {
|
||||
viewData[BINDING_INDEX] = bindingRootIndex;
|
||||
const hostCtx = unwrapRNode(viewData[currentDirectiveIndex]);
|
||||
setActiveHost(hostCtx, currentElementIndex);
|
||||
instruction(RenderFlags.Update, hostCtx, currentElementIndex);
|
||||
setActiveHost(null);
|
||||
|
||||
// Each directive gets a uniqueId value that is the same for both
|
||||
// create and update calls when the hostBindings function is called. The
|
||||
// directive uniqueId is not set anywhere--it is just incremented between
|
||||
// each hostBindings call and is useful for helping instruction code
|
||||
// uniquely determine which directive is currently active when executed.
|
||||
incrementActiveDirectiveId();
|
||||
}
|
||||
currentDirectiveIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
setActiveHostElement(null);
|
||||
}
|
||||
|
||||
/** Refreshes content queries for all directives in the given view. */
|
||||
|
@ -897,15 +906,27 @@ function invokeDirectivesHostBindings(tView: TView, viewData: LView, tNode: TNod
|
|||
const end = tNode.directiveEnd;
|
||||
const expando = tView.expandoInstructions !;
|
||||
const firstTemplatePass = tView.firstTemplatePass;
|
||||
const elementIndex = tNode.index - HEADER_OFFSET;
|
||||
setActiveHostElement(elementIndex);
|
||||
|
||||
for (let i = start; i < end; i++) {
|
||||
const def = tView.data[i] as DirectiveDef<any>;
|
||||
const directive = viewData[i];
|
||||
if (def.hostBindings) {
|
||||
invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstTemplatePass);
|
||||
|
||||
// Each directive gets a uniqueId value that is the same for both
|
||||
// create and update calls when the hostBindings function is called. The
|
||||
// directive uniqueId is not set anywhere--it is just incremented between
|
||||
// each hostBindings call and is useful for helping instruction code
|
||||
// uniquely determine which directive is currently active when executed.
|
||||
incrementActiveDirectiveId();
|
||||
} else if (firstTemplatePass) {
|
||||
expando.push(null);
|
||||
}
|
||||
}
|
||||
|
||||
setActiveHostElement(null);
|
||||
}
|
||||
|
||||
export function invokeHostBindingsInCreationMode(
|
||||
|
@ -914,9 +935,7 @@ export function invokeHostBindingsInCreationMode(
|
|||
const previousExpandoLength = expando.length;
|
||||
setCurrentDirectiveDef(def);
|
||||
const elementIndex = tNode.index - HEADER_OFFSET;
|
||||
setActiveHost(directive, elementIndex);
|
||||
def.hostBindings !(RenderFlags.Create, directive, elementIndex);
|
||||
setActiveHost(null);
|
||||
setCurrentDirectiveDef(null);
|
||||
// `hostBindings` function may or may not contain `allocHostVars` call
|
||||
// (e.g. it may not if it only contains host listeners), so we need to check whether
|
||||
|
|
|
@ -6,19 +6,24 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||
import {TNode} from '../interfaces/node';
|
||||
import {TNode, TNodeType} from '../interfaces/node';
|
||||
import {PlayerFactory} from '../interfaces/player';
|
||||
import {FLAGS, HEADER_OFFSET, LViewFlags, RENDERER, RootContextFlags} from '../interfaces/view';
|
||||
import {getActiveHostContext, getActiveHostElementIndex, getLView, getPreviousOrParentTNode} from '../state';
|
||||
import {getActiveDirectiveId, getActiveDirectiveSuperClassDepth, getLView, getPreviousOrParentTNode, getSelectedIndex} from '../state';
|
||||
import {getInitialClassNameValue, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from '../styling/class_and_style_bindings';
|
||||
import {ParamsOf, enqueueHostInstruction, registerHostDirective} from '../styling/host_instructions_queue';
|
||||
import {BoundPlayerFactory} from '../styling/player_factory';
|
||||
import {allocateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContext, hasClassInput, hasStyleInput} from '../styling/util';
|
||||
import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from '../styling/shared';
|
||||
import {allocateOrUpdateDirectiveIntoContext, createEmptyStylingContext, forceClassesAsString, forceStylesAsString, getStylingContext, hasClassInput, hasStyleInput} from '../styling/util';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {renderStringify} from '../util/misc_utils';
|
||||
import {getRootContext} from '../util/view_traversal_utils';
|
||||
import {getTNode} from '../util/view_utils';
|
||||
|
||||
import {scheduleTick, setInputsForProperty} from './shared';
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The contents of this file include the instructions for all styling-related
|
||||
* operations in Angular.
|
||||
|
@ -40,7 +45,6 @@ import {scheduleTick, setInputsForProperty} from './shared';
|
|||
* - elementHostStylingApply
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Allocates style and class binding properties on the element during creation mode.
|
||||
*
|
||||
|
@ -74,7 +78,9 @@ export function elementStyling(
|
|||
// components) then they will be applied at the end of the `elementEnd`
|
||||
// instruction (because directives are created first before styling is
|
||||
// executed for a new element).
|
||||
initElementStyling(tNode, classBindingNames, styleBindingNames, styleSanitizer, null);
|
||||
initElementStyling(
|
||||
tNode, classBindingNames, styleBindingNames, styleSanitizer,
|
||||
DEFAULT_TEMPLATE_DIRECTIVE_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,25 +114,28 @@ export function elementHostStyling(
|
|||
tNode.stylingTemplate = createEmptyStylingContext();
|
||||
}
|
||||
|
||||
const directive = getActiveHostContext();
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
|
||||
// despite the binding being applied in a queue (below), the allocation
|
||||
// of the directive into the context happens right away. The reason for
|
||||
// this is to retain the ordering of the directives (which is important
|
||||
// for the prioritization of bindings).
|
||||
allocateDirectiveIntoContext(tNode.stylingTemplate, directive);
|
||||
allocateOrUpdateDirectiveIntoContext(tNode.stylingTemplate, directiveStylingIndex);
|
||||
|
||||
const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || [];
|
||||
fns.push(
|
||||
() => initElementStyling(
|
||||
tNode, classBindingNames, styleBindingNames, styleSanitizer, directive));
|
||||
fns.push(() => {
|
||||
initElementStyling(
|
||||
tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex);
|
||||
registerHostDirective(tNode.stylingTemplate !, directiveStylingIndex);
|
||||
});
|
||||
}
|
||||
|
||||
function initElementStyling(
|
||||
tNode: TNode, classBindingNames?: string[] | null, styleBindingNames?: string[] | null,
|
||||
styleSanitizer?: StyleSanitizeFn | null, directive?: {} | null): void {
|
||||
tNode: TNode, classBindingNames: string[] | null | undefined,
|
||||
styleBindingNames: string[] | null | undefined,
|
||||
styleSanitizer: StyleSanitizeFn | null | undefined, directiveStylingIndex: number): void {
|
||||
updateContextWithBindings(
|
||||
tNode.stylingTemplate !, directive || null, classBindingNames, styleBindingNames,
|
||||
tNode.stylingTemplate !, directiveStylingIndex, classBindingNames, styleBindingNames,
|
||||
styleSanitizer);
|
||||
}
|
||||
|
||||
|
@ -160,7 +169,10 @@ function initElementStyling(
|
|||
export function elementStyleProp(
|
||||
index: number, styleIndex: number, value: string | number | String | PlayerFactory | null,
|
||||
suffix?: string | null, forceOverride?: boolean): void {
|
||||
elementStylePropInternal(null, index, styleIndex, value, suffix, forceOverride);
|
||||
const valueToAdd = resolveStylePropValue(value, suffix);
|
||||
updateElementStyleProp(
|
||||
getStylingContext(index + HEADER_OFFSET, getLView()), styleIndex, valueToAdd,
|
||||
DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,15 +203,20 @@ export function elementStyleProp(
|
|||
export function elementHostStyleProp(
|
||||
styleIndex: number, value: string | number | String | PlayerFactory | null,
|
||||
suffix?: string | null, forceOverride?: boolean): void {
|
||||
elementStylePropInternal(
|
||||
getActiveHostContext() !, getActiveHostElementIndex() !, styleIndex, value, suffix,
|
||||
forceOverride);
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
const hostElementIndex = getSelectedIndex();
|
||||
|
||||
const lView = getLView();
|
||||
const stylingContext = getStylingContext(hostElementIndex + HEADER_OFFSET, lView);
|
||||
|
||||
const valueToAdd = resolveStylePropValue(value, suffix);
|
||||
const args: ParamsOf<typeof updateElementStyleProp> =
|
||||
[stylingContext, styleIndex, valueToAdd, directiveStylingIndex, forceOverride];
|
||||
enqueueHostInstruction(stylingContext, directiveStylingIndex, updateElementStyleProp, args);
|
||||
}
|
||||
|
||||
function elementStylePropInternal(
|
||||
directive: {} | null, index: number, styleIndex: number,
|
||||
value: string | number | String | PlayerFactory | null, suffix?: string | null,
|
||||
forceOverride?: boolean): void {
|
||||
function resolveStylePropValue(
|
||||
value: string | number | String | PlayerFactory | null, suffix: string | null | undefined) {
|
||||
let valueToAdd: string|null = null;
|
||||
if (value !== null) {
|
||||
if (suffix) {
|
||||
|
@ -214,9 +231,7 @@ function elementStylePropInternal(
|
|||
valueToAdd = value as any as string;
|
||||
}
|
||||
}
|
||||
updateElementStyleProp(
|
||||
getStylingContext(index + HEADER_OFFSET, getLView()), styleIndex, valueToAdd, directive,
|
||||
forceOverride);
|
||||
return valueToAdd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -241,7 +256,12 @@ function elementStylePropInternal(
|
|||
export function elementClassProp(
|
||||
index: number, classIndex: number, value: boolean | PlayerFactory,
|
||||
forceOverride?: boolean): void {
|
||||
elementClassPropInternal(null, index, classIndex, value, forceOverride);
|
||||
const input = (value instanceof BoundPlayerFactory) ?
|
||||
(value as BoundPlayerFactory<boolean|null>) :
|
||||
booleanOrNull(value);
|
||||
updateElementClassProp(
|
||||
getStylingContext(index + HEADER_OFFSET, getLView()), classIndex, input,
|
||||
DEFAULT_TEMPLATE_DIRECTIVE_INDEX, forceOverride);
|
||||
}
|
||||
|
||||
|
||||
|
@ -265,19 +285,19 @@ export function elementClassProp(
|
|||
*/
|
||||
export function elementHostClassProp(
|
||||
classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void {
|
||||
elementClassPropInternal(
|
||||
getActiveHostContext() !, getActiveHostElementIndex() !, classIndex, value, forceOverride);
|
||||
}
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
const hostElementIndex = getSelectedIndex();
|
||||
|
||||
const lView = getLView();
|
||||
const stylingContext = getStylingContext(hostElementIndex + HEADER_OFFSET, lView);
|
||||
|
||||
function elementClassPropInternal(
|
||||
directive: {} | null, index: number, classIndex: number, value: boolean | PlayerFactory,
|
||||
forceOverride?: boolean): void {
|
||||
const input = (value instanceof BoundPlayerFactory) ?
|
||||
(value as BoundPlayerFactory<boolean|null>) :
|
||||
booleanOrNull(value);
|
||||
updateElementClassProp(
|
||||
getStylingContext(index + HEADER_OFFSET, getLView()), classIndex, input, directive,
|
||||
forceOverride);
|
||||
|
||||
const args: ParamsOf<typeof updateElementClassProp> =
|
||||
[stylingContext, classIndex, input, directiveStylingIndex, forceOverride];
|
||||
enqueueHostInstruction(stylingContext, directiveStylingIndex, updateElementClassProp, args);
|
||||
}
|
||||
|
||||
function booleanOrNull(value: any): boolean|null {
|
||||
|
@ -309,7 +329,30 @@ function booleanOrNull(value: any): boolean|null {
|
|||
export function elementStylingMap(
|
||||
index: number, classes: {[key: string]: any} | string | NO_CHANGE | null,
|
||||
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
||||
elementStylingMapInternal(null, index, classes, styles);
|
||||
const lView = getLView();
|
||||
const tNode = getTNode(index, lView);
|
||||
const stylingContext = getStylingContext(index + HEADER_OFFSET, lView);
|
||||
|
||||
// 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 (hasClassInput(tNode) && classes !== NO_CHANGE) {
|
||||
const initialClasses = getInitialClassNameValue(stylingContext);
|
||||
const classInputVal =
|
||||
(initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes);
|
||||
setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal);
|
||||
classes = NO_CHANGE;
|
||||
}
|
||||
|
||||
if (hasStyleInput(tNode) && styles !== NO_CHANGE) {
|
||||
const initialStyles = getInitialClassNameValue(stylingContext);
|
||||
const styleInputVal =
|
||||
(initialStyles.length ? (initialStyles + ' ') : '') + forceStylesAsString(styles);
|
||||
setInputsForProperty(lView, tNode.inputs !['style'] !, styleInputVal);
|
||||
styles = NO_CHANGE;
|
||||
}
|
||||
|
||||
updateStylingMap(stylingContext, classes, styles);
|
||||
}
|
||||
|
||||
|
||||
|
@ -339,39 +382,15 @@ export function elementStylingMap(
|
|||
export function elementHostStylingMap(
|
||||
classes: {[key: string]: any} | string | NO_CHANGE | null,
|
||||
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
||||
elementStylingMapInternal(
|
||||
getActiveHostContext() !, getActiveHostElementIndex() !, classes, styles);
|
||||
}
|
||||
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||
const hostElementIndex = getSelectedIndex();
|
||||
|
||||
function elementStylingMapInternal(
|
||||
directive: {} | null, index: number, classes: {[key: string]: any} | string | NO_CHANGE | null,
|
||||
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
||||
const lView = getLView();
|
||||
const tNode = getTNode(index, lView);
|
||||
const stylingContext = getStylingContext(index + HEADER_OFFSET, lView);
|
||||
const stylingContext = getStylingContext(hostElementIndex + HEADER_OFFSET, lView);
|
||||
|
||||
// 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 (!directive) {
|
||||
if (hasClassInput(tNode) && classes !== NO_CHANGE) {
|
||||
const initialClasses = getInitialClassNameValue(stylingContext);
|
||||
const classInputVal =
|
||||
(initialClasses.length ? (initialClasses + ' ') : '') + forceClassesAsString(classes);
|
||||
setInputsForProperty(lView, tNode.inputs !['class'] !, classInputVal);
|
||||
classes = NO_CHANGE;
|
||||
}
|
||||
|
||||
if (hasStyleInput(tNode) && styles !== NO_CHANGE) {
|
||||
const initialStyles = getInitialClassNameValue(stylingContext);
|
||||
const styleInputVal =
|
||||
(initialStyles.length ? (initialStyles + ' ') : '') + forceStylesAsString(styles);
|
||||
setInputsForProperty(lView, tNode.inputs !['style'] !, styleInputVal);
|
||||
styles = NO_CHANGE;
|
||||
}
|
||||
}
|
||||
|
||||
updateStylingMap(stylingContext, classes, styles, directive);
|
||||
const args: ParamsOf<typeof updateStylingMap> =
|
||||
[stylingContext, classes, styles, directiveStylingIndex];
|
||||
enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStylingMap, args);
|
||||
}
|
||||
|
||||
|
||||
|
@ -387,7 +406,7 @@ function elementStylingMapInternal(
|
|||
* @publicApi
|
||||
*/
|
||||
export function elementStylingApply(index: number): void {
|
||||
elementStylingApplyInternal(null, index);
|
||||
elementStylingApplyInternal(DEFAULT_TEMPLATE_DIRECTIVE_INDEX, index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -401,17 +420,33 @@ export function elementStylingApply(index: number): void {
|
|||
* @publicApi
|
||||
*/
|
||||
export function elementHostStylingApply(): void {
|
||||
elementStylingApplyInternal(getActiveHostContext() !, getActiveHostElementIndex() !);
|
||||
elementStylingApplyInternal(getActiveDirectiveStylingIndex(), getSelectedIndex());
|
||||
}
|
||||
|
||||
export function elementStylingApplyInternal(directive: {} | null, index: number): void {
|
||||
export function elementStylingApplyInternal(directiveStylingIndex: number, index: number): void {
|
||||
const lView = getLView();
|
||||
const tNode = getTNode(index, lView);
|
||||
|
||||
// if a non-element value is being processed then we can't render values
|
||||
// on the element at all therefore by setting the renderer to null then
|
||||
// the styling apply code knows not to actually apply the values...
|
||||
const renderer = tNode.type === TNodeType.Element ? lView[RENDERER] : null;
|
||||
const isFirstRender = (lView[FLAGS] & LViewFlags.FirstLViewPass) !== 0;
|
||||
const stylingContext = getStylingContext(index + HEADER_OFFSET, lView);
|
||||
const totalPlayersQueued = renderStyling(
|
||||
getStylingContext(index + HEADER_OFFSET, lView), lView[RENDERER], lView, isFirstRender, null,
|
||||
null, directive);
|
||||
stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex);
|
||||
if (totalPlayersQueued > 0) {
|
||||
const rootContext = getRootContext(lView);
|
||||
scheduleTick(rootContext, RootContextFlags.FlushPlayers);
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveDirectiveStylingIndex() {
|
||||
// whenever a directive's hostBindings function is called a uniqueId value
|
||||
// is assigned. Normally this is enough to help distinguish one directive
|
||||
// from another for the styling context, but there are situations where a
|
||||
// sub-class directive could inherit and assign styling in concert with a
|
||||
// parent directive. To help the styling code distinguish between a parent
|
||||
// sub-classed directive the inheritance depth is taken into account as well.
|
||||
return getActiveDirectiveId() + getActiveDirectiveSuperClassDepth();
|
||||
}
|
|
@ -309,6 +309,21 @@ export interface StylingContext extends
|
|||
*/
|
||||
[StylingIndex.CachedMultiStyles]: any|MapBasedOffsetValues;
|
||||
|
||||
/**
|
||||
* A queue of all hostStyling instructions.
|
||||
*
|
||||
* This array (queue) is populated only when host-level styling instructions
|
||||
* (e.g. `hostStylingMap` and `hostClassProp`) are used to apply style and
|
||||
* class values via host bindings to the host element. Despite these being
|
||||
* standard angular instructions, they are not designed to immediately apply
|
||||
* their values to the styling context when executed. What happens instead is
|
||||
* a queue is constructed and each instruction is populated into the queue.
|
||||
* Then, once the style/class values are set to flush (via `elementStylingApply` or
|
||||
* `hostStylingApply`), the queue is flushed and the values are rendered onto
|
||||
* the host element.
|
||||
*/
|
||||
[StylingIndex.HostInstructionsQueue]: HostInstructionsQueue|null;
|
||||
|
||||
/**
|
||||
* Location of animation context (which contains the active players) for this element styling
|
||||
* context.
|
||||
|
@ -316,6 +331,66 @@ export interface StylingContext extends
|
|||
[StylingIndex.PlayerContext]: PlayerContext|null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A queue of all host-related styling instructions (these are buffered and evaluated just before
|
||||
* the styling is applied).
|
||||
*
|
||||
* This queue is used when any `hostStyling` instructions are executed from the `hostBindings`
|
||||
* function. Template-level styling functions (e.g. `elementStylingMap` and `elementClassProp`)
|
||||
* do not make use of this queue (they are applied to the styling context immediately).
|
||||
*
|
||||
* Due to the nature of how components/directives are evaluated, directives (both parent and
|
||||
* subclass directives) may not apply their styling at the right time for the styling
|
||||
* algorithm code to prioritize them. Therefore, all host-styling instructions are queued up
|
||||
* (buffered) into the array below and are automatically sorted in terms of priority. The
|
||||
* priority for host-styling is as follows:
|
||||
*
|
||||
* 1. The template (this doesn't get queued, but gets evaluated immediately)
|
||||
* 2. Any directives present on the host
|
||||
* 2a) first child directive styling bindings are updated
|
||||
* 2b) then any parent directives
|
||||
* 3. Component host bindings
|
||||
*
|
||||
* Angular runs change detection for each of these cases in a different order. Because of this
|
||||
* the array below is populated with each of the host styling functions + their arguments.
|
||||
*
|
||||
* context[HostInstructionsQueue] = [
|
||||
* directiveIndex,
|
||||
* hostStylingFn,
|
||||
* [argumentsForFn],
|
||||
* ...
|
||||
* anotherDirectiveIndex, <-- this has a lower priority (a higher directive index)
|
||||
* anotherHostStylingFn,
|
||||
* [argumentsForFn],
|
||||
* ]
|
||||
*
|
||||
* When `renderStyling` is called (within `class_and_host_bindings.ts`) then the queue is
|
||||
* drained and each of the instructions are executed. Once complete the queue is empty then
|
||||
* the style/class binding code is rendered on the element (which is what happens normally
|
||||
* inside of `renderStyling`).
|
||||
*
|
||||
* Right now each directive's hostBindings function, as well the template function, both
|
||||
* call `elementStylingApply()` and `hostStylingApply()`. The fact that this is called
|
||||
* multiple times for the same element (b/c of change detection) causes some issues. To avoid
|
||||
* having styling code be rendered on an element multiple times, the `HostInstructionsQueue`
|
||||
* reserves a slot for a reference pointing to the very last directive that was registered and
|
||||
* only allows for styling to be applied once that directive is encountered (which will happen
|
||||
* as the last update for that element).
|
||||
*/
|
||||
export interface HostInstructionsQueue extends Array<number|Function|any[]> { [0]: number; }
|
||||
|
||||
/**
|
||||
* Used as a reference for any values contained within `HostInstructionsQueue`.
|
||||
*/
|
||||
export const enum HostInstructionsQueueIndex {
|
||||
LastRegisteredDirectiveIndexPosition = 0,
|
||||
ValuesStartPosition = 1,
|
||||
DirectiveIndexOffset = 0,
|
||||
InstructionFnOffset = 1,
|
||||
ParamsOffset = 2,
|
||||
Size = 3,
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a styling array to house static class and style values that were extracted
|
||||
* by the compiler and placed in the animation context via `elementStart` and
|
||||
|
@ -511,9 +586,7 @@ export const enum InitialStylingValuesIndex {
|
|||
* index value by the size of the array entries (so if DirA is at spot 8 then its index will be 2).
|
||||
*/
|
||||
export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|StyleSanitizeFn> {
|
||||
[DirectiveRegistryValuesIndex.DirectiveValueOffset]: null;
|
||||
[DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset]: number;
|
||||
[DirectiveRegistryValuesIndex.DirtyFlagOffset]: boolean;
|
||||
[DirectiveRegistryValuesIndex.StyleSanitizerOffset]: StyleSanitizeFn|null;
|
||||
}
|
||||
|
||||
|
@ -522,11 +595,9 @@ export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|St
|
|||
* that are housed inside of [DirectiveRegistryValues].
|
||||
*/
|
||||
export const enum DirectiveRegistryValuesIndex {
|
||||
DirectiveValueOffset = 0,
|
||||
SinglePropValuesIndexOffset = 1,
|
||||
DirtyFlagOffset = 2,
|
||||
StyleSanitizerOffset = 3,
|
||||
Size = 4
|
||||
SinglePropValuesIndexOffset = 0,
|
||||
StyleSanitizerOffset = 1,
|
||||
Size = 2
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -678,9 +749,10 @@ export const enum StylingIndex {
|
|||
CachedMultiStyles = 7,
|
||||
// Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue
|
||||
// Position of where the initial styles are stored in the styling context
|
||||
PlayerContext = 8,
|
||||
HostInstructionsQueue = 8,
|
||||
PlayerContext = 9,
|
||||
// Location of single (prop) value entries are stored within the context
|
||||
SingleStylesStartPosition = 9,
|
||||
SingleStylesStartPosition = 10,
|
||||
FlagsOffset = 0,
|
||||
PropertyOffset = 1,
|
||||
ValueOffset = 2,
|
||||
|
@ -705,3 +777,13 @@ export const enum DirectiveOwnerAndPlayerBuilderIndex {
|
|||
BitCountSize = 16,
|
||||
BitMask = 0b1111111111111111
|
||||
}
|
||||
|
||||
/**
|
||||
* The default directive styling index value for template-based bindings.
|
||||
*
|
||||
* All host-level bindings (e.g. `hostStyleProp` and `hostStylingMap`) are
|
||||
* assigned a directive styling index value based on the current directive
|
||||
* uniqueId and the directive super-class inheritance depth. But for template
|
||||
* bindings they always have the same directive styling index value.
|
||||
*/
|
||||
export const DEFAULT_TEMPLATE_DIRECTIVE_INDEX = 0;
|
||||
|
|
|
@ -119,27 +119,139 @@ export function getLView(): LView {
|
|||
return lView;
|
||||
}
|
||||
|
||||
let activeHostContext: {}|null = null;
|
||||
let activeHostElementIndex: number|null = null;
|
||||
/**
|
||||
* Used as the starting directive id value.
|
||||
*
|
||||
* All subsequent directives are incremented from this value onwards.
|
||||
* The reason why this value is `1` instead of `0` is because the `0`
|
||||
* value is reserved for the template.
|
||||
*/
|
||||
const MIN_DIRECTIVE_ID = 1;
|
||||
|
||||
let activeDirectiveId = MIN_DIRECTIVE_ID;
|
||||
|
||||
/**
|
||||
* Sets the active host context (the directive/component instance) and its host element index.
|
||||
*
|
||||
* @param host the directive/component instance
|
||||
* @param index the element index value for the host element where the directive/component instance
|
||||
* lives
|
||||
* Position depth (with respect from leaf to root) in a directive sub-class inheritance chain.
|
||||
*/
|
||||
export function setActiveHost(host: {} | null, index: number | null = null) {
|
||||
activeHostContext = host;
|
||||
activeHostElementIndex = index;
|
||||
let activeDirectiveSuperClassDepthPosition = 0;
|
||||
|
||||
/**
|
||||
* Total count of how many directives are a part of an inheritance chain.
|
||||
*
|
||||
* When directives are sub-classed (extended) from one to another, Angular
|
||||
* needs to keep track of exactly how many were encountered so it can accurately
|
||||
* generate the next directive id (once the next directive id is visited).
|
||||
* Normally the next directive id just a single incremented value from the
|
||||
* previous one, however, if the previous directive is a part of an inheritance
|
||||
* chain (a series of sub-classed directives) then the incremented value must
|
||||
* also take into account the total amount of sub-classed values.
|
||||
*
|
||||
* Note that this value resets back to zero once the next directive is
|
||||
* visited (when `incrementActiveDirectiveId` or `setActiveHostElement`
|
||||
* is called).
|
||||
*/
|
||||
let activeDirectiveSuperClassHeight = 0;
|
||||
|
||||
/**
|
||||
* Sets the active directive host element and resets the directive id value
|
||||
* (when the provided elementIndex value has changed).
|
||||
*
|
||||
* @param elementIndex the element index value for the host element where
|
||||
* the directive/component instance lives
|
||||
*/
|
||||
export function setActiveHostElement(elementIndex: number | null = null) {
|
||||
if (_selectedIndex !== elementIndex) {
|
||||
setSelectedIndex(elementIndex == null ? -1 : elementIndex);
|
||||
activeDirectiveId = MIN_DIRECTIVE_ID;
|
||||
activeDirectiveSuperClassDepthPosition = 0;
|
||||
activeDirectiveSuperClassHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveHostContext() {
|
||||
return activeHostContext;
|
||||
/**
|
||||
* Returns the current id value of the current directive.
|
||||
*
|
||||
* For example we have an element that has two directives on it:
|
||||
* <div dir-one dir-two></div>
|
||||
*
|
||||
* dirOne->hostBindings() (id == 1)
|
||||
* dirTwo->hostBindings() (id == 2)
|
||||
*
|
||||
* Note that this is only active when `hostBinding` functions are being processed.
|
||||
*
|
||||
* Note that directive id values are specific to an element (this means that
|
||||
* the same id value could be present on another element with a completely
|
||||
* different set of directives).
|
||||
*/
|
||||
export function getActiveDirectiveId() {
|
||||
return activeDirectiveId;
|
||||
}
|
||||
|
||||
export function getActiveHostElementIndex() {
|
||||
return activeHostElementIndex;
|
||||
/**
|
||||
* Increments the current directive id value.
|
||||
*
|
||||
* For example we have an element that has two directives on it:
|
||||
* <div dir-one dir-two></div>
|
||||
*
|
||||
* dirOne->hostBindings() (index = 1)
|
||||
* // increment
|
||||
* dirTwo->hostBindings() (index = 2)
|
||||
*
|
||||
* Depending on whether or not a previous directive had any inherited
|
||||
* directives present, that value will be incremented in addition
|
||||
* to the id jumping up by one.
|
||||
*
|
||||
* Note that this is only active when `hostBinding` functions are being processed.
|
||||
*
|
||||
* Note that directive id values are specific to an element (this means that
|
||||
* the same id value could be present on another element with a completely
|
||||
* different set of directives).
|
||||
*/
|
||||
export function incrementActiveDirectiveId() {
|
||||
activeDirectiveId += 1 + activeDirectiveSuperClassHeight;
|
||||
|
||||
// because we are dealing with a new directive this
|
||||
// means we have exited out of the inheritance chain
|
||||
activeDirectiveSuperClassDepthPosition = 0;
|
||||
activeDirectiveSuperClassHeight = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current super class (reverse inheritance) position depth for a directive.
|
||||
*
|
||||
* For example we have two directives: Child and Other (but Child is a sub-class of Parent)
|
||||
* <div child-dir other-dir></div>
|
||||
*
|
||||
* // increment
|
||||
* parentInstance->hostBindings() (depth = 1)
|
||||
* // decrement
|
||||
* childInstance->hostBindings() (depth = 0)
|
||||
* otherInstance->hostBindings() (depth = 0 b/c it's a different directive)
|
||||
*
|
||||
* Note that this is only active when `hostBinding` functions are being processed.
|
||||
*/
|
||||
export function adjustActiveDirectiveSuperClassDepthPosition(delta: number) {
|
||||
activeDirectiveSuperClassDepthPosition += delta;
|
||||
|
||||
// we keep track of the height value so that when the next directive is visited
|
||||
// then Angular knows to generate a new directive id value which has taken into
|
||||
// account how many sub-class directives were a part of the previous directive.
|
||||
activeDirectiveSuperClassHeight =
|
||||
Math.max(activeDirectiveSuperClassHeight, activeDirectiveSuperClassDepthPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current super class (reverse inheritance) depth for a directive.
|
||||
*
|
||||
* This is designed to help instruction code distinguish different hostBindings
|
||||
* calls from each other when a directive has extended from another directive.
|
||||
* Normally using the directive id value is enough, but with the case
|
||||
* of parent/sub-class directive inheritance more information is required.
|
||||
*
|
||||
* Note that this is only active when `hostBinding` functions are being processed.
|
||||
*/
|
||||
export function getActiveDirectiveSuperClassDepth() {
|
||||
return activeDirectiveSuperClassDepthPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,14 +10,14 @@ import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
|||
import {AttributeMarker, TAttributes} from '../interfaces/node';
|
||||
import {BindingStore, BindingType, Player, PlayerBuilder, PlayerFactory, PlayerIndex} from '../interfaces/player';
|
||||
import {RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
|
||||
import {DirectiveOwnerAndPlayerBuilderIndex, DirectiveRegistryValues, DirectiveRegistryValuesIndex, InitialStylingValues, InitialStylingValuesIndex, MapBasedOffsetValues, MapBasedOffsetValuesIndex, SinglePropOffsetValues, SinglePropOffsetValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
|
||||
import {DirectiveOwnerAndPlayerBuilderIndex, DirectiveRegistryValuesIndex, InitialStylingValues, InitialStylingValuesIndex, MapBasedOffsetValues, MapBasedOffsetValuesIndex, SinglePropOffsetValues, SinglePropOffsetValuesIndex, StylingContext, StylingFlags, StylingIndex} from '../interfaces/styling';
|
||||
import {LView, RootContext} from '../interfaces/view';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
import {getRootContext} from '../util/view_traversal_utils';
|
||||
|
||||
import {allowFlush as allowHostInstructionsQueueFlush, flushQueue as flushHostInstructionsQueue} from './host_instructions_queue';
|
||||
import {BoundPlayerFactory} from './player_factory';
|
||||
import {addPlayerInternal, allocPlayerContext, allocateDirectiveIntoContext, createEmptyStylingContext, getPlayerContext} from './util';
|
||||
|
||||
import {addPlayerInternal, allocPlayerContext, allocateOrUpdateDirectiveIntoContext, createEmptyStylingContext, getPlayerContext} from './util';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -42,9 +42,9 @@ import {addPlayerInternal, allocPlayerContext, allocateDirectiveIntoContext, cre
|
|||
* Creates a new StylingContext an fills it with the provided static styling attribute values.
|
||||
*/
|
||||
export function initializeStaticContext(
|
||||
attrs: TAttributes, stylingStartIndex: number, directiveRef?: any | null): StylingContext {
|
||||
attrs: TAttributes, stylingStartIndex: number, directiveIndex: number = 0): StylingContext {
|
||||
const context = createEmptyStylingContext();
|
||||
patchContextWithStaticAttrs(context, attrs, stylingStartIndex, directiveRef);
|
||||
patchContextWithStaticAttrs(context, attrs, stylingStartIndex, directiveIndex);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -57,25 +57,14 @@ export function initializeStaticContext(
|
|||
* assigned to the context
|
||||
* @param attrsStylingStartIndex what index to start iterating within the
|
||||
* provided `attrs` array to start reading style and class values
|
||||
* @param directiveRef the directive instance with which static data is associated with.
|
||||
*/
|
||||
export function patchContextWithStaticAttrs(
|
||||
context: StylingContext, attrs: TAttributes, attrsStylingStartIndex: number,
|
||||
directiveRef?: any | null): void {
|
||||
directiveIndex: number): void {
|
||||
// this means the context has already been set and instantiated
|
||||
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
||||
|
||||
// If the styling context has already been patched with the given directive's bindings,
|
||||
// then there is no point in doing it again. The reason why this may happen (the directive
|
||||
// styling being patched twice) is because the `stylingBinding` function is called each time
|
||||
// an element is created (both within a template function and within directive host bindings).
|
||||
const directives = context[StylingIndex.DirectiveRegistryPosition];
|
||||
let detectedIndex = getDirectiveRegistryValuesIndexOf(directives, directiveRef || null);
|
||||
if (detectedIndex === -1) {
|
||||
// this is a new directive which we have not seen yet.
|
||||
detectedIndex = allocateDirectiveIntoContext(context, directiveRef);
|
||||
}
|
||||
const directiveIndex = detectedIndex / DirectiveRegistryValuesIndex.Size;
|
||||
allocateOrUpdateDirectiveIntoContext(context, directiveIndex);
|
||||
|
||||
let initialClasses: InitialStylingValues|null = null;
|
||||
let initialStyles: InitialStylingValues|null = null;
|
||||
|
@ -199,7 +188,6 @@ export function allowNewBindingsForStylingContext(context: StylingContext): bool
|
|||
* reference the provided directive.
|
||||
*
|
||||
* @param context the existing styling context
|
||||
* @param directiveRef the directive that the new bindings will reference
|
||||
* @param classBindingNames an array of class binding names that will be added to the context
|
||||
* @param styleBindingNames an array of style binding names that will be added to the context
|
||||
* @param styleSanitizer an optional sanitizer that handle all sanitization on for each of
|
||||
|
@ -207,13 +195,14 @@ export function allowNewBindingsForStylingContext(context: StylingContext): bool
|
|||
* instance will only be active if and when the directive updates the bindings that it owns.
|
||||
*/
|
||||
export function updateContextWithBindings(
|
||||
context: StylingContext, directiveRef: any | null, classBindingNames?: string[] | null,
|
||||
context: StylingContext, directiveIndex: number, classBindingNames?: string[] | null,
|
||||
styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null) {
|
||||
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
||||
|
||||
// this means the context has already been patched with the directive's bindings
|
||||
const directiveIndex = findOrPatchDirectiveIntoRegistry(context, directiveRef, styleSanitizer);
|
||||
if (directiveIndex === -1) {
|
||||
const isNewDirective =
|
||||
findOrPatchDirectiveIntoRegistry(context, directiveIndex, false, styleSanitizer);
|
||||
if (!isNewDirective) {
|
||||
// this means the directive has already been patched in ... No point in doing anything
|
||||
return;
|
||||
}
|
||||
|
@ -470,46 +459,22 @@ export function updateContextWithBindings(
|
|||
* Searches through the existing registry of directives
|
||||
*/
|
||||
export function findOrPatchDirectiveIntoRegistry(
|
||||
context: StylingContext, directiveRef: any, styleSanitizer?: StyleSanitizeFn | null) {
|
||||
const directiveRefs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
const nextOffsetInsertionIndex = context[StylingIndex.SinglePropOffsetPositions].length;
|
||||
context: StylingContext, directiveIndex: number, staticModeOnly: boolean,
|
||||
styleSanitizer?: StyleSanitizeFn | null): boolean {
|
||||
const directiveRegistry = context[StylingIndex.DirectiveRegistryPosition];
|
||||
const index = directiveIndex * DirectiveRegistryValuesIndex.Size;
|
||||
const singlePropStartPosition = index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||
|
||||
let directiveIndex: number;
|
||||
let detectedIndex = getDirectiveRegistryValuesIndexOf(directiveRefs, directiveRef);
|
||||
// this means that the directive has already been registered into the registry
|
||||
if (index < directiveRegistry.length &&
|
||||
(directiveRegistry[singlePropStartPosition] as number) >= 0)
|
||||
return false;
|
||||
|
||||
if (detectedIndex === -1) {
|
||||
detectedIndex = directiveRefs.length;
|
||||
directiveIndex = directiveRefs.length / DirectiveRegistryValuesIndex.Size;
|
||||
|
||||
allocateDirectiveIntoContext(context, directiveRef);
|
||||
directiveRefs[detectedIndex + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] =
|
||||
nextOffsetInsertionIndex;
|
||||
directiveRefs[detectedIndex + DirectiveRegistryValuesIndex.StyleSanitizerOffset] =
|
||||
styleSanitizer || null;
|
||||
} else {
|
||||
const singlePropStartPosition =
|
||||
detectedIndex + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||
if (directiveRefs[singlePropStartPosition] ! >= 0) {
|
||||
// the directive has already been patched into the context
|
||||
return -1;
|
||||
}
|
||||
|
||||
directiveIndex = detectedIndex / DirectiveRegistryValuesIndex.Size;
|
||||
|
||||
// because the directive already existed this means that it was set during elementHostAttrs or
|
||||
// elementStart which means that the binding values were not here. Therefore, the values below
|
||||
// need to be applied so that single class and style properties can be assigned later.
|
||||
const singlePropPositionIndex =
|
||||
detectedIndex + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||
directiveRefs[singlePropPositionIndex] = nextOffsetInsertionIndex;
|
||||
|
||||
// the sanitizer is also apart of the binding process and will be used when bindings are
|
||||
// applied.
|
||||
const styleSanitizerIndex = detectedIndex + DirectiveRegistryValuesIndex.StyleSanitizerOffset;
|
||||
directiveRefs[styleSanitizerIndex] = styleSanitizer || null;
|
||||
}
|
||||
|
||||
return directiveIndex;
|
||||
const singlePropsStartIndex =
|
||||
staticModeOnly ? -1 : context[StylingIndex.SinglePropOffsetPositions].length;
|
||||
allocateOrUpdateDirectiveIntoContext(
|
||||
context, directiveIndex, singlePropsStartIndex, styleSanitizer);
|
||||
return true;
|
||||
}
|
||||
|
||||
function getMatchingBindingIndex(
|
||||
|
@ -543,18 +508,13 @@ function getMatchingBindingIndex(
|
|||
* newly provided style values.
|
||||
* @param classesInput The key/value map of CSS class names that will be used for the update.
|
||||
* @param stylesInput The key/value map of CSS styles that will be used for the update.
|
||||
* @param directiveRef an optional reference to the directive responsible
|
||||
* for this binding change. If present then style binding will only
|
||||
* actualize if the directive has ownership over this binding
|
||||
* (see styling.ts#directives for more information about the algorithm).
|
||||
*/
|
||||
export function updateStylingMap(
|
||||
context: StylingContext, classesInput: {[key: string]: any} | string |
|
||||
BoundPlayerFactory<null|string|{[key: string]: any}>| null,
|
||||
stylesInput?: {[key: string]: any} | BoundPlayerFactory<null|{[key: string]: any}>| null,
|
||||
directiveRef?: any): void {
|
||||
const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
||||
|
||||
directiveIndex: number = 0): void {
|
||||
ngDevMode && assertValidDirectiveIndex(context, directiveIndex);
|
||||
classesInput = classesInput || null;
|
||||
stylesInput = stylesInput || null;
|
||||
const ignoreAllClassUpdates = isMultiValueCacheHit(context, true, directiveIndex, classesInput);
|
||||
|
@ -887,7 +847,6 @@ function patchStylingMapIntoContext(
|
|||
|
||||
if (dirty) {
|
||||
setContextDirty(context, true);
|
||||
setDirectiveDirty(context, directiveIndex, true);
|
||||
}
|
||||
|
||||
return totalNewAllocatedSlots;
|
||||
|
@ -901,18 +860,14 @@ function patchStylingMapIntoContext(
|
|||
* newly provided class value.
|
||||
* @param offset The index of the CSS class which is being updated.
|
||||
* @param addOrRemove Whether or not to add or remove the CSS class
|
||||
* @param directiveRef an optional reference to the directive responsible
|
||||
* for this binding change. If present then style binding will only
|
||||
* actualize if the directive has ownership over this binding
|
||||
* (see styling.ts#directives for more information about the algorithm).
|
||||
* @param forceOverride whether or not to skip all directive prioritization
|
||||
* and just apply the value regardless.
|
||||
*/
|
||||
export function updateClassProp(
|
||||
context: StylingContext, offset: number,
|
||||
input: boolean | BoundPlayerFactory<boolean|null>| null, directiveRef?: any,
|
||||
input: boolean | BoundPlayerFactory<boolean|null>| null, directiveIndex: number = 0,
|
||||
forceOverride?: boolean): void {
|
||||
updateSingleStylingValue(context, offset, input, true, directiveRef, forceOverride);
|
||||
updateSingleStylingValue(context, offset, input, true, directiveIndex, forceOverride);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -928,25 +883,21 @@ export function updateClassProp(
|
|||
* newly provided style value.
|
||||
* @param offset The index of the property which is being updated.
|
||||
* @param value The CSS style value that will be assigned
|
||||
* @param directiveRef an optional reference to the directive responsible
|
||||
* for this binding change. If present then style binding will only
|
||||
* actualize if the directive has ownership over this binding
|
||||
* (see styling.ts#directives for more information about the algorithm).
|
||||
* @param forceOverride whether or not to skip all directive prioritization
|
||||
* and just apply the value regardless.
|
||||
*/
|
||||
export function updateStyleProp(
|
||||
context: StylingContext, offset: number,
|
||||
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>, directiveRef?: any,
|
||||
forceOverride?: boolean): void {
|
||||
updateSingleStylingValue(context, offset, input, false, directiveRef, forceOverride);
|
||||
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>,
|
||||
directiveIndex: number = 0, forceOverride?: boolean): void {
|
||||
updateSingleStylingValue(context, offset, input, false, directiveIndex, forceOverride);
|
||||
}
|
||||
|
||||
function updateSingleStylingValue(
|
||||
context: StylingContext, offset: number,
|
||||
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>, isClassBased: boolean,
|
||||
directiveRef: any, forceOverride?: boolean): void {
|
||||
const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
||||
directiveIndex: number, forceOverride?: boolean): void {
|
||||
ngDevMode && assertValidDirectiveIndex(context, directiveIndex);
|
||||
const singleIndex = getSinglePropIndexValue(context, directiveIndex, offset, isClassBased);
|
||||
const currValue = getValue(context, singleIndex);
|
||||
const currFlag = getPointers(context, singleIndex);
|
||||
|
@ -1001,7 +952,6 @@ function updateSingleStylingValue(
|
|||
|
||||
setDirty(context, indexForMulti, multiDirty);
|
||||
setDirty(context, singleIndex, singleDirty);
|
||||
setDirectiveDirty(context, directiveIndex, true);
|
||||
setContextDirty(context, true);
|
||||
}
|
||||
|
||||
|
@ -1029,120 +979,128 @@ function updateSingleStylingValue(
|
|||
* to this key/value map instead of being renderered via the renderer.
|
||||
* @param stylesStore if provided, the updated style values will be applied
|
||||
* to this key/value map instead of being renderered via the renderer.
|
||||
* @param directiveRef an optional directive that will be used to target which
|
||||
* styling values are rendered. If left empty, only the bindings that are
|
||||
* registered on the template will be rendered.
|
||||
* @returns number the total amount of players that got queued for animation (if any)
|
||||
*/
|
||||
export function renderStyling(
|
||||
context: StylingContext, renderer: Renderer3, rootOrView: RootContext | LView,
|
||||
context: StylingContext, renderer: Renderer3 | null, rootOrView: RootContext | LView,
|
||||
isFirstRender: boolean, classesStore?: BindingStore | null, stylesStore?: BindingStore | null,
|
||||
directiveRef?: any): number {
|
||||
directiveIndex: number = 0): number {
|
||||
let totalPlayersQueued = 0;
|
||||
const targetDirectiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
||||
|
||||
if (isContextDirty(context) && isDirectiveDirty(context, targetDirectiveIndex)) {
|
||||
const flushPlayerBuilders: any =
|
||||
context[StylingIndex.MasterFlagPosition] & StylingFlags.PlayerBuildersDirty;
|
||||
const native = context[StylingIndex.ElementPosition] !;
|
||||
const multiStartIndex = getMultiStylesStartIndex(context);
|
||||
// this prevents multiple attempts to render style/class values on
|
||||
// the same element...
|
||||
if (allowHostInstructionsQueueFlush(context, directiveIndex)) {
|
||||
// all styling instructions present within any hostBindings functions
|
||||
// do not update the context immediately when called. They are instead
|
||||
// queued up and applied to the context right at this point. Why? This
|
||||
// is because Angular evaluates component/directive and directive
|
||||
// sub-class code at different points and it's important that the
|
||||
// styling values are applied to the context in the right order
|
||||
// (see `interfaces/styling.ts` for more information).
|
||||
flushHostInstructionsQueue(context);
|
||||
|
||||
let stillDirty = false;
|
||||
for (let i = StylingIndex.SingleStylesStartPosition; i < context.length;
|
||||
i += StylingIndex.Size) {
|
||||
// there is no point in rendering styles that have not changed on screen
|
||||
if (isDirty(context, i)) {
|
||||
const flag = getPointers(context, i);
|
||||
const directiveIndex = getDirectiveIndexFromEntry(context, i);
|
||||
if (targetDirectiveIndex !== directiveIndex) {
|
||||
stillDirty = true;
|
||||
continue;
|
||||
}
|
||||
if (isContextDirty(context)) {
|
||||
// this is here to prevent things like <ng-container [style] [class]>...</ng-container>
|
||||
// or if there are any host style or class bindings present in a directive set on
|
||||
// a container node
|
||||
const native = context[StylingIndex.ElementPosition] !as HTMLElement;
|
||||
|
||||
const prop = getProp(context, i);
|
||||
const value = getValue(context, i);
|
||||
const styleSanitizer =
|
||||
(flag & StylingFlags.Sanitize) ? getStyleSanitizer(context, directiveIndex) : null;
|
||||
const playerBuilder = getPlayerBuilder(context, i);
|
||||
const isClassBased = flag & StylingFlags.Class ? true : false;
|
||||
const isInSingleRegion = i < multiStartIndex;
|
||||
const flushPlayerBuilders: any =
|
||||
context[StylingIndex.MasterFlagPosition] & StylingFlags.PlayerBuildersDirty;
|
||||
const multiStartIndex = getMultiStylesStartIndex(context);
|
||||
|
||||
let valueToApply: string|boolean|null = value;
|
||||
for (let i = StylingIndex.SingleStylesStartPosition; i < context.length;
|
||||
i += StylingIndex.Size) {
|
||||
// there is no point in rendering styles that have not changed on screen
|
||||
if (isDirty(context, i)) {
|
||||
const flag = getPointers(context, i);
|
||||
const directiveIndex = getDirectiveIndexFromEntry(context, i);
|
||||
const prop = getProp(context, i);
|
||||
const value = getValue(context, i);
|
||||
const styleSanitizer =
|
||||
(flag & StylingFlags.Sanitize) ? getStyleSanitizer(context, directiveIndex) : null;
|
||||
const playerBuilder = getPlayerBuilder(context, i);
|
||||
const isClassBased = flag & StylingFlags.Class ? true : false;
|
||||
const isInSingleRegion = i < multiStartIndex;
|
||||
|
||||
// VALUE DEFER CASE 1: Use a multi value instead of a null single value
|
||||
// this check implies that a single value was removed and we
|
||||
// should now defer to a multi value and use that (if set).
|
||||
if (isInSingleRegion && !valueExists(valueToApply, isClassBased)) {
|
||||
// single values ALWAYS have a reference to a multi index
|
||||
const multiIndex = getMultiOrSingleIndex(flag);
|
||||
valueToApply = getValue(context, multiIndex);
|
||||
}
|
||||
let valueToApply: string|boolean|null = value;
|
||||
|
||||
// VALUE DEFER CASE 2: Use the initial value if all else fails (is falsy)
|
||||
// the initial value will always be a string or null,
|
||||
// therefore we can safely adopt it in case there's nothing else
|
||||
// note that this should always be a falsy check since `false` is used
|
||||
// for both class and style comparisons (styles can't be false and false
|
||||
// classes are turned off and should therefore defer to their initial values)
|
||||
// Note that we ignore class-based deferals because otherwise a class can never
|
||||
// be removed in the case that it exists as true in the initial classes list...
|
||||
if (!valueExists(valueToApply, isClassBased)) {
|
||||
valueToApply = getInitialValue(context, flag);
|
||||
}
|
||||
|
||||
// if the first render is true then we do not want to start applying falsy
|
||||
// values to the DOM element's styling. Otherwise then we know there has
|
||||
// been a change and even if it's falsy then it's removing something that
|
||||
// was truthy before.
|
||||
const doApplyValue = isFirstRender ? valueToApply : true;
|
||||
if (doApplyValue) {
|
||||
if (isClassBased) {
|
||||
setClass(
|
||||
native, prop, valueToApply ? true : false, renderer, classesStore, playerBuilder);
|
||||
} else {
|
||||
setStyle(
|
||||
native, prop, valueToApply as string | null, renderer, styleSanitizer, stylesStore,
|
||||
playerBuilder);
|
||||
// VALUE DEFER CASE 1: Use a multi value instead of a null single value
|
||||
// this check implies that a single value was removed and we
|
||||
// should now defer to a multi value and use that (if set).
|
||||
if (isInSingleRegion && !valueExists(valueToApply, isClassBased)) {
|
||||
// single values ALWAYS have a reference to a multi index
|
||||
const multiIndex = getMultiOrSingleIndex(flag);
|
||||
valueToApply = getValue(context, multiIndex);
|
||||
}
|
||||
}
|
||||
|
||||
setDirty(context, i, false);
|
||||
}
|
||||
}
|
||||
// VALUE DEFER CASE 2: Use the initial value if all else fails (is falsy)
|
||||
// the initial value will always be a string or null,
|
||||
// therefore we can safely adopt it in case there's nothing else
|
||||
// note that this should always be a falsy check since `false` is used
|
||||
// for both class and style comparisons (styles can't be false and false
|
||||
// classes are turned off and should therefore defer to their initial values)
|
||||
// Note that we ignore class-based deferals because otherwise a class can never
|
||||
// be removed in the case that it exists as true in the initial classes list...
|
||||
if (!valueExists(valueToApply, isClassBased)) {
|
||||
valueToApply = getInitialValue(context, flag);
|
||||
}
|
||||
|
||||
if (flushPlayerBuilders) {
|
||||
const rootContext =
|
||||
Array.isArray(rootOrView) ? getRootContext(rootOrView) : rootOrView as RootContext;
|
||||
const playerContext = getPlayerContext(context) !;
|
||||
const playersStartIndex = playerContext[PlayerIndex.NonBuilderPlayersStart];
|
||||
for (let i = PlayerIndex.PlayerBuildersStartPosition; i < playersStartIndex;
|
||||
i += PlayerIndex.PlayerAndPlayerBuildersTupleSize) {
|
||||
const builder = playerContext[i] as ClassAndStylePlayerBuilder<any>| null;
|
||||
const playerInsertionIndex = i + PlayerIndex.PlayerOffsetPosition;
|
||||
const oldPlayer = playerContext[playerInsertionIndex] as Player | null;
|
||||
if (builder) {
|
||||
const player = builder.buildPlayer(oldPlayer, isFirstRender);
|
||||
if (player !== undefined) {
|
||||
if (player != null) {
|
||||
const wasQueued = addPlayerInternal(
|
||||
playerContext, rootContext, native as HTMLElement, player, playerInsertionIndex);
|
||||
wasQueued && totalPlayersQueued++;
|
||||
}
|
||||
if (oldPlayer) {
|
||||
oldPlayer.destroy();
|
||||
// if the first render is true then we do not want to start applying falsy
|
||||
// values to the DOM element's styling. Otherwise then we know there has
|
||||
// been a change and even if it's falsy then it's removing something that
|
||||
// was truthy before.
|
||||
const doApplyValue = renderer && (isFirstRender ? valueToApply : true);
|
||||
if (doApplyValue) {
|
||||
if (isClassBased) {
|
||||
setClass(
|
||||
native, prop, valueToApply ? true : false, renderer !, classesStore,
|
||||
playerBuilder);
|
||||
} else {
|
||||
setStyle(
|
||||
native, prop, valueToApply as string | null, renderer !, styleSanitizer,
|
||||
stylesStore, playerBuilder);
|
||||
}
|
||||
}
|
||||
} else if (oldPlayer) {
|
||||
// the player builder has been removed ... therefore we should delete the associated
|
||||
// player
|
||||
oldPlayer.destroy();
|
||||
|
||||
setDirty(context, i, false);
|
||||
}
|
||||
}
|
||||
setContextPlayersDirty(context, false);
|
||||
}
|
||||
|
||||
setDirectiveDirty(context, targetDirectiveIndex, false);
|
||||
setContextDirty(context, stillDirty);
|
||||
if (flushPlayerBuilders) {
|
||||
const rootContext =
|
||||
Array.isArray(rootOrView) ? getRootContext(rootOrView) : rootOrView as RootContext;
|
||||
const playerContext = getPlayerContext(context) !;
|
||||
const playersStartIndex = playerContext[PlayerIndex.NonBuilderPlayersStart];
|
||||
for (let i = PlayerIndex.PlayerBuildersStartPosition; i < playersStartIndex;
|
||||
i += PlayerIndex.PlayerAndPlayerBuildersTupleSize) {
|
||||
const builder = playerContext[i] as ClassAndStylePlayerBuilder<any>| null;
|
||||
const playerInsertionIndex = i + PlayerIndex.PlayerOffsetPosition;
|
||||
const oldPlayer = playerContext[playerInsertionIndex] as Player | null;
|
||||
if (builder) {
|
||||
const player = builder.buildPlayer(oldPlayer, isFirstRender);
|
||||
if (player !== undefined) {
|
||||
if (player != null) {
|
||||
const wasQueued = addPlayerInternal(
|
||||
playerContext, rootContext, native as HTMLElement, player,
|
||||
playerInsertionIndex);
|
||||
wasQueued && totalPlayersQueued++;
|
||||
}
|
||||
if (oldPlayer) {
|
||||
oldPlayer.destroy();
|
||||
}
|
||||
}
|
||||
} else if (oldPlayer) {
|
||||
// the player builder has been removed ... therefore we should delete the associated
|
||||
// player
|
||||
oldPlayer.destroy();
|
||||
}
|
||||
}
|
||||
setContextPlayersDirty(context, false);
|
||||
}
|
||||
|
||||
setContextDirty(context, false);
|
||||
}
|
||||
}
|
||||
|
||||
return totalPlayersQueued;
|
||||
|
@ -1622,43 +1580,6 @@ export function getDirectiveIndexFromEntry(context: StylingContext, index: numbe
|
|||
return value & DirectiveOwnerAndPlayerBuilderIndex.BitMask;
|
||||
}
|
||||
|
||||
function getDirectiveIndexFromRegistry(context: StylingContext, directiveRef: any) {
|
||||
let directiveIndex: number;
|
||||
|
||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
let index = getDirectiveRegistryValuesIndexOf(dirs, directiveRef);
|
||||
if (index === -1) {
|
||||
// if the directive was not allocated then this means that styling is
|
||||
// being applied in a dynamic way AFTER the element was already instantiated
|
||||
index = dirs.length;
|
||||
directiveIndex = index > 0 ? index / DirectiveRegistryValuesIndex.Size : 0;
|
||||
|
||||
dirs.push(null, null, null, null);
|
||||
dirs[index + DirectiveRegistryValuesIndex.DirectiveValueOffset] = directiveRef;
|
||||
dirs[index + DirectiveRegistryValuesIndex.DirtyFlagOffset] = false;
|
||||
dirs[index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] = -1;
|
||||
|
||||
const classesStartIndex =
|
||||
getMultiClassesStartIndex(context) || StylingIndex.SingleStylesStartPosition;
|
||||
registerMultiMapEntry(context, directiveIndex, true, context.length);
|
||||
registerMultiMapEntry(context, directiveIndex, false, classesStartIndex);
|
||||
} else {
|
||||
directiveIndex = index > 0 ? index / DirectiveRegistryValuesIndex.Size : 0;
|
||||
}
|
||||
|
||||
return directiveIndex;
|
||||
}
|
||||
|
||||
function getDirectiveRegistryValuesIndexOf(
|
||||
directives: DirectiveRegistryValues, directive: {}): number {
|
||||
for (let i = 0; i < directives.length; i += DirectiveRegistryValuesIndex.Size) {
|
||||
if (directives[i] === directive) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function getInitialStylingValuesIndexOf(keyValues: InitialStylingValues, key: string): number {
|
||||
for (let i = InitialStylingValuesIndex.KeyValueStartPosition; i < keyValues.length;
|
||||
i += InitialStylingValuesIndex.Size) {
|
||||
|
@ -1724,21 +1645,6 @@ function getStyleSanitizer(context: StylingContext, directiveIndex: number): Sty
|
|||
return value as StyleSanitizeFn | null;
|
||||
}
|
||||
|
||||
function isDirectiveDirty(context: StylingContext, directiveIndex: number): boolean {
|
||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
return dirs
|
||||
[directiveIndex * DirectiveRegistryValuesIndex.Size +
|
||||
DirectiveRegistryValuesIndex.DirtyFlagOffset] as boolean;
|
||||
}
|
||||
|
||||
function setDirectiveDirty(
|
||||
context: StylingContext, directiveIndex: number, dirtyYes: boolean): void {
|
||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
dirs
|
||||
[directiveIndex * DirectiveRegistryValuesIndex.Size +
|
||||
DirectiveRegistryValuesIndex.DirtyFlagOffset] = dirtyYes;
|
||||
}
|
||||
|
||||
function allowValueChange(
|
||||
currentValue: string | boolean | null, newValue: string | boolean | null,
|
||||
currentDirectiveOwner: number, newDirectiveOwner: number) {
|
||||
|
@ -1994,3 +1900,12 @@ function addOrUpdateStaticStyle(
|
|||
staticStyles[index + InitialStylingValuesIndex.DirectiveOwnerOffset] = directiveOwnerIndex;
|
||||
return index;
|
||||
}
|
||||
|
||||
function assertValidDirectiveIndex(context: StylingContext, directiveIndex: number) {
|
||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
const index = directiveIndex * DirectiveRegistryValuesIndex.Size;
|
||||
if (index >= dirs.length ||
|
||||
dirs[index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] === -1) {
|
||||
throw new Error('The provided directive is not registered with the styling context');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {HostInstructionsQueue, HostInstructionsQueueIndex, StylingContext, StylingIndex} from '../interfaces/styling';
|
||||
import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from '../styling/shared';
|
||||
|
||||
/*
|
||||
* This file contains the logic to defer all hostBindings-related styling code to run
|
||||
* at a later point, instead of immediately (as is the case with how template-level
|
||||
* styling instructions are run).
|
||||
*
|
||||
* Certain styling instructions, present within directives, components and sub-classed
|
||||
* directives, are evaluated at different points (depending on priority) and will therefore
|
||||
* not be applied to the styling context of an element immediately. They are instead
|
||||
* designed to be applied just before styling is applied to an element.
|
||||
*
|
||||
* (The priority for when certain host-related styling operations are executed is discussed
|
||||
* more within `interfaces/styling.ts`.)
|
||||
*/
|
||||
|
||||
export function registerHostDirective(context: StylingContext, directiveIndex: number) {
|
||||
let buffer = context[StylingIndex.HostInstructionsQueue];
|
||||
if (!buffer) {
|
||||
buffer = context[StylingIndex.HostInstructionsQueue] = [DEFAULT_TEMPLATE_DIRECTIVE_INDEX];
|
||||
}
|
||||
buffer[HostInstructionsQueueIndex.LastRegisteredDirectiveIndexPosition] = directiveIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues a styling instruction to be run just before `renderStyling()` is executed.
|
||||
*/
|
||||
export function enqueueHostInstruction<T extends Function>(
|
||||
context: StylingContext, priority: number, instructionFn: T, instructionFnArgs: ParamsOf<T>) {
|
||||
const buffer: HostInstructionsQueue = context[StylingIndex.HostInstructionsQueue] !;
|
||||
const index = findNextInsertionIndex(buffer, priority);
|
||||
buffer.splice(index, 0, priority, instructionFn, instructionFnArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Figures out where exactly to to insert the next host instruction queue entry.
|
||||
*/
|
||||
function findNextInsertionIndex(buffer: HostInstructionsQueue, priority: number): number {
|
||||
for (let i = HostInstructionsQueueIndex.ValuesStartPosition; i < buffer.length;
|
||||
i += HostInstructionsQueueIndex.Size) {
|
||||
const p = buffer[i + HostInstructionsQueueIndex.DirectiveIndexOffset] as number;
|
||||
if (p > priority) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the host instructions queue (if present within the provided
|
||||
* context) and executes each queued instruction entry.
|
||||
*/
|
||||
export function flushQueue(context: StylingContext): void {
|
||||
const buffer = context[StylingIndex.HostInstructionsQueue];
|
||||
if (buffer) {
|
||||
for (let i = HostInstructionsQueueIndex.ValuesStartPosition; i < buffer.length;
|
||||
i += HostInstructionsQueueIndex.Size) {
|
||||
const fn = buffer[i + HostInstructionsQueueIndex.InstructionFnOffset] as Function;
|
||||
const args = buffer[i + HostInstructionsQueueIndex.ParamsOffset] as any[];
|
||||
fn(...args);
|
||||
}
|
||||
buffer.length = HostInstructionsQueueIndex.ValuesStartPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not to allow the host instructions queue to be flushed or not.
|
||||
*
|
||||
* Because the hostBindings function code is unaware of the presence of other host bindings
|
||||
* (as well as the template function) then styling is evaluated multiple times per element.
|
||||
* To prevent style and class values from being applied to the element multiple times, a
|
||||
* flush is only allowed when the last directive (the directive that was registered into
|
||||
* the styling context) attempts to render its styling.
|
||||
*/
|
||||
export function allowFlush(context: StylingContext, directiveIndex: number): boolean {
|
||||
const buffer = context[StylingIndex.HostInstructionsQueue];
|
||||
if (buffer) {
|
||||
return buffer[HostInstructionsQueueIndex.LastRegisteredDirectiveIndexPosition] ===
|
||||
directiveIndex;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infers the parameters of a given function into a typed array.
|
||||
*/
|
||||
export type ParamsOf<T> = T extends(...args: infer T) => any ? T : never;
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* The default directive styling index value for template-based bindings.
|
||||
*
|
||||
* All host-level bindings (e.g. `hostStyleProp` and `hostStylingMap`) are
|
||||
* assigned a directive styling index value based on the current directive
|
||||
* uniqueId and the directive super-class inheritance depth. But for template
|
||||
* bindings they always have the same directive styling index value.
|
||||
*/
|
||||
export const DEFAULT_TEMPLATE_DIRECTIVE_INDEX = 0;
|
|
@ -19,6 +19,7 @@ import {HEADER_OFFSET, HOST, LView, RootContext} from '../interfaces/view';
|
|||
import {getTNode, isStylingContext} from '../util/view_utils';
|
||||
|
||||
import {CorePlayerHandler} from './core_player_handler';
|
||||
import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from './shared';
|
||||
|
||||
export const ANIMATION_PROP_PREFIX = '@';
|
||||
|
||||
|
@ -35,12 +36,13 @@ export function createEmptyStylingContext(
|
|||
[0, 0], // SinglePropOffsets
|
||||
[0], // CachedMultiClassValue
|
||||
[0], // CachedMultiStyleValue
|
||||
null, // HostBuffer
|
||||
null, // PlayerContext
|
||||
];
|
||||
|
||||
// whenever a context is created there is always a `null` directive
|
||||
// that is registered (which is a placeholder for the "template").
|
||||
allocateDirectiveIntoContext(context, null);
|
||||
allocateOrUpdateDirectiveIntoContext(context, DEFAULT_TEMPLATE_DIRECTIVE_INDEX);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -60,25 +62,28 @@ export function createEmptyStylingContext(
|
|||
* @param directiveRef the directive that will be allocated into the context
|
||||
* @returns the index where the directive was inserted into
|
||||
*/
|
||||
export function allocateDirectiveIntoContext(
|
||||
context: StylingContext, directiveRef: any | null): number {
|
||||
// this is a new directive which we have not seen yet.
|
||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
||||
const i = dirs.length;
|
||||
export function allocateOrUpdateDirectiveIntoContext(
|
||||
context: StylingContext, directiveIndex: number, singlePropValuesIndex: number = -1,
|
||||
styleSanitizer?: StyleSanitizeFn | null | undefined): void {
|
||||
const directiveRegistry = context[StylingIndex.DirectiveRegistryPosition];
|
||||
|
||||
const index = directiveIndex * DirectiveRegistryValuesIndex.Size;
|
||||
// we preemptively make space into the directives array and then
|
||||
// assign values slot-by-slot to ensure that if the directive ordering
|
||||
// changes then it will still function
|
||||
dirs.push(null, null, null, null);
|
||||
dirs[i + DirectiveRegistryValuesIndex.DirectiveValueOffset] = directiveRef;
|
||||
dirs[i + DirectiveRegistryValuesIndex.DirtyFlagOffset] = false;
|
||||
dirs[i + DirectiveRegistryValuesIndex.StyleSanitizerOffset] = null;
|
||||
const limit = index + DirectiveRegistryValuesIndex.Size;
|
||||
for (let i = directiveRegistry.length; i < limit; i += DirectiveRegistryValuesIndex.Size) {
|
||||
// -1 is used to signal that the directive has been allocated, but
|
||||
// no actual style or class bindings have been registered yet...
|
||||
directiveRegistry.push(-1, null);
|
||||
}
|
||||
|
||||
// -1 is used to signal that the directive has been allocated, but
|
||||
// no actual style or class bindings have been registered yet...
|
||||
dirs[i + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] = -1;
|
||||
|
||||
return i;
|
||||
const propValuesStartPosition = index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||
if (singlePropValuesIndex >= 0 && directiveRegistry[propValuesStartPosition] === -1) {
|
||||
directiveRegistry[propValuesStartPosition] = singlePropValuesIndex;
|
||||
directiveRegistry[index + DirectiveRegistryValuesIndex.StyleSanitizerOffset] =
|
||||
styleSanitizer || null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,12 +11,12 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
|||
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
describe('acceptance integration tests', () => {
|
||||
onlyInIvy('[style] and [class] bindings are a new feature')
|
||||
onlyInIvy('map-based [style] and [class] bindings are not supported in VE')
|
||||
.it('should render host bindings on the root component', () => {
|
||||
@Component({template: '...'})
|
||||
class MyApp {
|
||||
@HostBinding('style') public myStylesExp = {};
|
||||
@HostBinding('class') public myClassesExp = {};
|
||||
@HostBinding('style') myStylesExp = {};
|
||||
@HostBinding('class') myClassesExp = {};
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyApp]});
|
||||
|
@ -153,4 +153,166 @@ describe('acceptance integration tests', () => {
|
|||
expect(element.style.width).toEqual('300px');
|
||||
expect(element.classList.contains('abc')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render styling for parent and sub-classed components in order', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<child-and-parent-cmp></child-and-parent-cmp>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
@Component({template: '...'})
|
||||
class ParentCmp {
|
||||
@HostBinding('style.width') width1 = '100px';
|
||||
@HostBinding('style.height') height1 = '100px';
|
||||
@HostBinding('style.opacity') opacity1 = '0.5';
|
||||
}
|
||||
|
||||
@Component({selector: 'child-and-parent-cmp', template: '...'})
|
||||
class ChildCmp extends ParentCmp {
|
||||
@HostBinding('style.width') width2 = '200px';
|
||||
@HostBinding('style.height') height2 = '200px';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyApp, ParentCmp, ChildCmp]});
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
const element = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
|
||||
const childElement = element.querySelector('child-and-parent-cmp');
|
||||
expect(childElement.style.width).toEqual('200px');
|
||||
expect(childElement.style.height).toEqual('200px');
|
||||
expect(childElement.style.opacity).toEqual('0.5');
|
||||
});
|
||||
|
||||
onlyInIvy('[style.prop] and [class.name] prioritization is a new feature')
|
||||
.it('should prioritize styling present in the order of directive hostBinding evaluation, but consider sub-classed directive styling to be the most important',
|
||||
() => {
|
||||
const log: string[] = [];
|
||||
|
||||
@Component({template: '<div child-dir sibling-dir></div>'})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
@Directive({selector: '[parent-dir]'})
|
||||
class ParentDir {
|
||||
@HostBinding('style.width')
|
||||
get width1() { return '100px'; }
|
||||
|
||||
@HostBinding('style.height')
|
||||
get height1() { return '100px'; }
|
||||
|
||||
@HostBinding('style.color')
|
||||
get color1() { return 'red'; }
|
||||
}
|
||||
|
||||
@Directive({selector: '[child-dir]'})
|
||||
class ChildDir extends ParentDir {
|
||||
@HostBinding('style.width')
|
||||
get width2() { return '200px'; }
|
||||
|
||||
@HostBinding('style.height')
|
||||
get height2() { return '200px'; }
|
||||
}
|
||||
|
||||
@Directive({selector: '[sibling-dir]'})
|
||||
class SiblingDir {
|
||||
@HostBinding('style.width')
|
||||
get width3() { return '300px'; }
|
||||
|
||||
@HostBinding('style.height')
|
||||
get height3() { return '300px'; }
|
||||
|
||||
@HostBinding('style.opacity')
|
||||
get opacity3() { return '0.5'; }
|
||||
|
||||
@HostBinding('style.color')
|
||||
get color1() { return 'blue'; }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule(
|
||||
{declarations: [MyApp, ParentDir, ChildDir, SiblingDir]});
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
const element = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
|
||||
const childElement = element.querySelector('div');
|
||||
|
||||
// width/height values were set in all directives, but the sub-class directive
|
||||
// (ChildDir)
|
||||
// had priority over the parent directive (ParentDir) which is why its value won. It
|
||||
// also
|
||||
// won over Dir because the SiblingDir directive was evaluated later on.
|
||||
expect(childElement.style.width).toEqual('200px');
|
||||
expect(childElement.style.height).toEqual('200px');
|
||||
|
||||
// ParentDir styled the color first before Dir
|
||||
expect(childElement.style.color).toEqual('red');
|
||||
|
||||
// Dir was the only directive to style opacity
|
||||
expect(childElement.style.opacity).toEqual('0.5');
|
||||
});
|
||||
|
||||
it('should ensure that static classes are assigned to ng-container elements and picked up for content projection',
|
||||
() => {
|
||||
@Component({
|
||||
template: `
|
||||
<project>
|
||||
outer
|
||||
<ng-container class="inner">
|
||||
inner
|
||||
</ng-container>
|
||||
</project>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'project',
|
||||
template: `
|
||||
<div class="outer-area">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
<div class="inner-area">
|
||||
<ng-content select=".inner"></ng-content>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
class ProjectCmp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyApp, ProjectCmp]});
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
const element = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
|
||||
const inner = element.querySelector('.inner-area');
|
||||
expect(inner.textContent.trim()).toEqual('inner');
|
||||
const outer = element.querySelector('.outer-area');
|
||||
expect(outer.textContent.trim()).toEqual('outer');
|
||||
});
|
||||
|
||||
it('should allow class-bindings to be placed on ng-container elements', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<ng-container [class.foo]="true" dir-that-adds-other-classes>...</ng-container>
|
||||
`
|
||||
})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
@Directive({selector: '[dir-that-adds-other-classes]'})
|
||||
class DirThatAddsOtherClasses {
|
||||
@HostBinding('class.other-class') bool = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [MyApp, DirThatAddsOtherClasses]});
|
||||
expect(() => {
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
fixture.detectChanges();
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
{
|
||||
"name": "DECLARATION_VIEW"
|
||||
},
|
||||
{
|
||||
"name": "DEFAULT_TEMPLATE_DIRECTIVE_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "DepComponent"
|
||||
},
|
||||
|
@ -158,6 +161,9 @@
|
|||
{
|
||||
"name": "_renderCompCount"
|
||||
},
|
||||
{
|
||||
"name": "_selectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "addComponentLogic"
|
||||
},
|
||||
|
@ -171,7 +177,7 @@
|
|||
"name": "allocStylingContext"
|
||||
},
|
||||
{
|
||||
"name": "allocateDirectiveIntoContext"
|
||||
"name": "allocateOrUpdateDirectiveIntoContext"
|
||||
},
|
||||
{
|
||||
"name": "allowValueChange"
|
||||
|
@ -338,9 +344,6 @@
|
|||
{
|
||||
"name": "getDirectiveDef"
|
||||
},
|
||||
{
|
||||
"name": "getDirectiveRegistryValuesIndexOf"
|
||||
},
|
||||
{
|
||||
"name": "getElementDepthCount"
|
||||
},
|
||||
|
@ -449,6 +452,9 @@
|
|||
{
|
||||
"name": "increaseElementDepthCount"
|
||||
},
|
||||
{
|
||||
"name": "incrementActiveDirectiveId"
|
||||
},
|
||||
{
|
||||
"name": "initNodeFlags"
|
||||
},
|
||||
|
@ -627,7 +633,7 @@
|
|||
"name": "saveResolvedLocalsInData"
|
||||
},
|
||||
{
|
||||
"name": "setActiveHost"
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
|
@ -668,6 +674,9 @@
|
|||
{
|
||||
"name": "setPreviousOrParentTNode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "setStyle"
|
||||
},
|
||||
|
|
|
@ -134,6 +134,9 @@
|
|||
{
|
||||
"name": "_renderCompCount"
|
||||
},
|
||||
{
|
||||
"name": "_selectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "addToViewTree"
|
||||
},
|
||||
|
@ -323,6 +326,9 @@
|
|||
{
|
||||
"name": "includeViewProviders"
|
||||
},
|
||||
{
|
||||
"name": "incrementActiveDirectiveId"
|
||||
},
|
||||
{
|
||||
"name": "initNodeFlags"
|
||||
},
|
||||
|
@ -435,7 +441,7 @@
|
|||
"name": "resetPreOrderHookFlags"
|
||||
},
|
||||
{
|
||||
"name": "setActiveHost"
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
|
@ -464,6 +470,9 @@
|
|||
{
|
||||
"name": "setPreviousOrParentTNode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "setStyle"
|
||||
},
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
{
|
||||
"name": "DECLARATION_VIEW"
|
||||
},
|
||||
{
|
||||
"name": "DEFAULT_TEMPLATE_DIRECTIVE_INDEX"
|
||||
},
|
||||
{
|
||||
"name": "DefaultIterableDiffer"
|
||||
},
|
||||
|
@ -371,6 +374,9 @@
|
|||
{
|
||||
"name": "_renderCompCount"
|
||||
},
|
||||
{
|
||||
"name": "_selectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "_symbolIterator"
|
||||
},
|
||||
|
@ -399,7 +405,10 @@
|
|||
"name": "allocStylingContext"
|
||||
},
|
||||
{
|
||||
"name": "allocateDirectiveIntoContext"
|
||||
"name": "allocateOrUpdateDirectiveIntoContext"
|
||||
},
|
||||
{
|
||||
"name": "allowFlush"
|
||||
},
|
||||
{
|
||||
"name": "allowValueChange"
|
||||
|
@ -572,9 +581,6 @@
|
|||
{
|
||||
"name": "elementClassProp"
|
||||
},
|
||||
{
|
||||
"name": "elementClassPropInternal"
|
||||
},
|
||||
{
|
||||
"name": "elementCreate"
|
||||
},
|
||||
|
@ -644,6 +650,9 @@
|
|||
{
|
||||
"name": "findViaComponent"
|
||||
},
|
||||
{
|
||||
"name": "flushQueue"
|
||||
},
|
||||
{
|
||||
"name": "forwardRef"
|
||||
},
|
||||
|
@ -698,12 +707,6 @@
|
|||
{
|
||||
"name": "getDirectiveIndexFromEntry"
|
||||
},
|
||||
{
|
||||
"name": "getDirectiveIndexFromRegistry"
|
||||
},
|
||||
{
|
||||
"name": "getDirectiveRegistryValuesIndexOf"
|
||||
},
|
||||
{
|
||||
"name": "getElementDepthCount"
|
||||
},
|
||||
|
@ -755,9 +758,6 @@
|
|||
{
|
||||
"name": "getMatchingBindingIndex"
|
||||
},
|
||||
{
|
||||
"name": "getMultiClassesStartIndex"
|
||||
},
|
||||
{
|
||||
"name": "getMultiOrSingleIndex"
|
||||
},
|
||||
|
@ -908,6 +908,9 @@
|
|||
{
|
||||
"name": "increaseElementDepthCount"
|
||||
},
|
||||
{
|
||||
"name": "incrementActiveDirectiveId"
|
||||
},
|
||||
{
|
||||
"name": "initElementStyling"
|
||||
},
|
||||
|
@ -983,9 +986,6 @@
|
|||
{
|
||||
"name": "isDifferent"
|
||||
},
|
||||
{
|
||||
"name": "isDirectiveDirty"
|
||||
},
|
||||
{
|
||||
"name": "isDirty"
|
||||
},
|
||||
|
@ -1224,7 +1224,7 @@
|
|||
"name": "select"
|
||||
},
|
||||
{
|
||||
"name": "setActiveHost"
|
||||
"name": "setActiveHostElement"
|
||||
},
|
||||
{
|
||||
"name": "setBindingRoot"
|
||||
|
@ -1247,9 +1247,6 @@
|
|||
{
|
||||
"name": "setCurrentQueryIndex"
|
||||
},
|
||||
{
|
||||
"name": "setDirectiveDirty"
|
||||
},
|
||||
{
|
||||
"name": "setDirty"
|
||||
},
|
||||
|
@ -1292,6 +1289,9 @@
|
|||
{
|
||||
"name": "setSanitizeFlag"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
{
|
||||
"name": "setStyle"
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,14 +16,5 @@
|
|||
// clang-format off
|
||||
// tslint:disable
|
||||
|
||||
window.testBlocklist = {
|
||||
"MatSidenav should be fixed position when in fixed mode": {
|
||||
"error": "Error: Expected ng-tns-c380-0 ng-trigger ng-trigger-transform mat-drawer mat-sidenav mat-drawer-over ng-star-inserted to contain 'mat-sidenav-fixed'.",
|
||||
"notes": "FW-1132: Host class bindings don't work if super class has host class bindings"
|
||||
},
|
||||
"MatSidenav should set fixed bottom and top when in fixed mode": {
|
||||
"error": "Error: Expected '' to be '20px'.",
|
||||
"notes": "FW-1132: Host class bindings don't work if super class has host class bindings"
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
window.testBlocklist = {};
|
||||
// clang-format on
|
Loading…
Reference in New Issue