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": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime": 1440,
|
"runtime": 1440,
|
||||||
"main": 14106,
|
"main": 14287,
|
||||||
"polyfills": 43567
|
"polyfills": 43567
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {PlayerHandler} from './interfaces/player';
|
||||||
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
|
||||||
import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, RENDERER, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
|
import {CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, RENDERER, RootContext, RootContextFlags, TVIEW} from './interfaces/view';
|
||||||
import {applyOnCreateInstructions} from './node_util';
|
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 {renderInitialClasses, renderInitialStyles} from './styling/class_and_style_bindings';
|
||||||
import {publishDefaultGlobalUtils} from './util/global_utils';
|
import {publishDefaultGlobalUtils} from './util/global_utils';
|
||||||
import {defaultScheduler, renderStringify} from './util/misc_utils';
|
import {defaultScheduler, renderStringify} from './util/misc_utils';
|
||||||
|
@ -210,10 +210,15 @@ export function createRootComponent<T>(
|
||||||
|
|
||||||
const rootTNode = getPreviousOrParentTNode();
|
const rootTNode = getPreviousOrParentTNode();
|
||||||
if (tView.firstTemplatePass && componentDef.hostBindings) {
|
if (tView.firstTemplatePass && componentDef.hostBindings) {
|
||||||
|
const elementIndex = rootTNode.index - HEADER_OFFSET;
|
||||||
|
setActiveHostElement(elementIndex);
|
||||||
|
|
||||||
const expando = tView.expandoInstructions !;
|
const expando = tView.expandoInstructions !;
|
||||||
invokeHostBindingsInCreationMode(
|
invokeHostBindingsInCreationMode(
|
||||||
componentDef, expando, component, rootTNode, tView.firstTemplatePass);
|
componentDef, expando, component, rootTNode, tView.firstTemplatePass);
|
||||||
rootTNode.onElementCreationFns && applyOnCreateInstructions(rootTNode);
|
rootTNode.onElementCreationFns && applyOnCreateInstructions(rootTNode);
|
||||||
|
|
||||||
|
setActiveHostElement(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rootTNode.stylingTemplate) {
|
if (rootTNode.stylingTemplate) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {Type} from '../../interface/type';
|
||||||
import {fillProperties} from '../../util/property';
|
import {fillProperties} from '../../util/property';
|
||||||
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
import {EMPTY_ARRAY, EMPTY_OBJ} from '../empty';
|
||||||
import {ComponentDef, DirectiveDef, DirectiveDefFeature, RenderFlags} from '../interfaces/definition';
|
import {ComponentDef, DirectiveDef, DirectiveDefFeature, RenderFlags} from '../interfaces/definition';
|
||||||
|
import {adjustActiveDirectiveSuperClassDepthPosition} from '../state';
|
||||||
import {isComponentDef} from '../util/view_utils';
|
import {isComponentDef} from '../util/view_utils';
|
||||||
|
|
||||||
import {NgOnChangesFeature} from './ng_onchanges_feature';
|
import {NgOnChangesFeature} from './ng_onchanges_feature';
|
||||||
|
@ -63,8 +64,24 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
|
||||||
const superHostBindings = superDef.hostBindings;
|
const superHostBindings = superDef.hostBindings;
|
||||||
if (superHostBindings) {
|
if (superHostBindings) {
|
||||||
if (prevHostBindings) {
|
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) => {
|
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);
|
prevHostBindings(rf, ctx, elementIndex);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,20 +11,23 @@ import {assertHasParent} from '../assert';
|
||||||
import {attachPatchData} from '../context_discovery';
|
import {attachPatchData} from '../context_discovery';
|
||||||
import {registerPostOrderHooks} from '../hooks';
|
import {registerPostOrderHooks} from '../hooks';
|
||||||
import {TAttributes, TNodeFlags, TNodeType} from '../interfaces/node';
|
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 {SanitizerFn} from '../interfaces/sanitization';
|
||||||
import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view';
|
import {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view';
|
||||||
import {assertNodeType} from '../node_assert';
|
import {assertNodeType} from '../node_assert';
|
||||||
import {appendChild} from '../node_manipulation';
|
import {appendChild} from '../node_manipulation';
|
||||||
import {applyOnCreateInstructions} from '../node_util';
|
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 {getInitialClassNameValue, getInitialStyleStringValue, initializeStaticContext, patchContextWithStaticAttrs, renderInitialClasses, renderInitialStyles} from '../styling/class_and_style_bindings';
|
||||||
import {getStylingContext, hasClassInput, hasStyleInput} from '../styling/util';
|
import {getStylingContext, hasClassInput, hasStyleInput} from '../styling/util';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils';
|
import {attrsStylingIndexOf, setUpAttributes} from '../util/attrs_utils';
|
||||||
import {renderStringify} from '../util/misc_utils';
|
import {renderStringify} from '../util/misc_utils';
|
||||||
import {getNativeByIndex, getNativeByTNode, getTNode} from '../util/view_utils';
|
import {getNativeByIndex, getNativeByTNode, getTNode} from '../util/view_utils';
|
||||||
|
|
||||||
import {createDirectivesAndLocals, createNodeAtIndex, elementCreate, executeContentQueries, initializeTNodeInputs, setInputsForProperty, setNodeStylingTemplate} from './shared';
|
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.
|
* Create DOM element. The instruction must later be followed by `elementEnd()` call.
|
||||||
|
@ -256,17 +259,26 @@ export function elementAttribute(
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export function elementHostAttrs(attrs: TAttributes) {
|
export function elementHostAttrs(attrs: TAttributes) {
|
||||||
const tNode = getPreviousOrParentTNode();
|
const hostElementIndex = getSelectedIndex();
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
const tNode = getTNode(hostElementIndex, lView);
|
||||||
const lastAttrIndex = setUpAttributes(native, attrs);
|
|
||||||
const stylingAttrsStartIndex = attrsStylingIndexOf(attrs, lastAttrIndex);
|
// non-element nodes (e.g. `<ng-container>`) are not rendered as actual
|
||||||
if (stylingAttrsStartIndex >= 0) {
|
// element nodes and adding styles/classes on to them will cause runtime
|
||||||
const directive = getActiveHostContext();
|
// errors...
|
||||||
if (tNode.stylingTemplate) {
|
if (tNode.type === TNodeType.Element) {
|
||||||
patchContextWithStaticAttrs(tNode.stylingTemplate, attrs, stylingAttrsStartIndex, directive);
|
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||||
} else {
|
const lastAttrIndex = setUpAttributes(native, attrs);
|
||||||
tNode.stylingTemplate = initializeStaticContext(attrs, stylingAttrsStartIndex, directive);
|
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 {BINDING_INDEX, QUERIES, RENDERER, TVIEW} from '../interfaces/view';
|
||||||
import {assertNodeType} from '../node_assert';
|
import {assertNodeType} from '../node_assert';
|
||||||
import {appendChild} from '../node_manipulation';
|
import {appendChild} from '../node_manipulation';
|
||||||
|
import {applyOnCreateInstructions} from '../node_util';
|
||||||
import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from '../state';
|
import {getIsParent, getLView, getPreviousOrParentTNode, setIsParent, setPreviousOrParentTNode} from '../state';
|
||||||
import {createDirectivesAndLocals, createNodeAtIndex, executeContentQueries, setNodeStylingTemplate} from './shared';
|
import {createDirectivesAndLocals, createNodeAtIndex, executeContentQueries, setNodeStylingTemplate} from './shared';
|
||||||
|
|
||||||
|
@ -83,5 +84,9 @@ export function elementContainerEnd(): void {
|
||||||
lView[QUERIES] = currentQueries.parent;
|
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);
|
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 {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 {assertNodeOfPossibleTypes, assertNodeType} from '../node_assert';
|
||||||
import {isNodeMatchingSelectorList} from '../node_selector_matcher';
|
import {isNodeMatchingSelectorList} from '../node_selector_matcher';
|
||||||
import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, 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 {initializeStaticContext as initializeStaticStylingContext} from '../styling/class_and_style_bindings';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {attrsStylingIndexOf} from '../util/attrs_utils';
|
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 {getLViewParent, getRootContext} from '../util/view_traversal_utils';
|
||||||
import {getComponentViewByIndex, getNativeByTNode, isComponentDef, isContentQueryHost, isRootView, readPatchedLView, resetPreOrderHookFlags, unwrapRNode, viewAttachedToChangeDetector} from '../util/view_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
|
* A permanent marker promise which signifies that the current CD tree is
|
||||||
* clean.
|
* 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
|
// Negative numbers mean that we are starting new EXPANDO block and need to update
|
||||||
// the current element and directive index.
|
// the current element and directive index.
|
||||||
currentElementIndex = -instruction;
|
currentElementIndex = -instruction;
|
||||||
|
setActiveHostElement(currentElementIndex);
|
||||||
|
|
||||||
// Injector block and providers are taken into account.
|
// Injector block and providers are taken into account.
|
||||||
const providerCount = (tView.expandoInstructions[++i] as number);
|
const providerCount = (tView.expandoInstructions[++i] as number);
|
||||||
bindingRootIndex += INJECTOR_BLOOM_PARENT_SIZE + providerCount;
|
bindingRootIndex += INJECTOR_BLOOM_PARENT_SIZE + providerCount;
|
||||||
|
@ -124,14 +127,20 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
||||||
if (instruction !== null) {
|
if (instruction !== null) {
|
||||||
viewData[BINDING_INDEX] = bindingRootIndex;
|
viewData[BINDING_INDEX] = bindingRootIndex;
|
||||||
const hostCtx = unwrapRNode(viewData[currentDirectiveIndex]);
|
const hostCtx = unwrapRNode(viewData[currentDirectiveIndex]);
|
||||||
setActiveHost(hostCtx, currentElementIndex);
|
|
||||||
instruction(RenderFlags.Update, 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++;
|
currentDirectiveIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setActiveHostElement(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Refreshes content queries for all directives in the given view. */
|
/** 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 end = tNode.directiveEnd;
|
||||||
const expando = tView.expandoInstructions !;
|
const expando = tView.expandoInstructions !;
|
||||||
const firstTemplatePass = tView.firstTemplatePass;
|
const firstTemplatePass = tView.firstTemplatePass;
|
||||||
|
const elementIndex = tNode.index - HEADER_OFFSET;
|
||||||
|
setActiveHostElement(elementIndex);
|
||||||
|
|
||||||
for (let i = start; i < end; i++) {
|
for (let i = start; i < end; i++) {
|
||||||
const def = tView.data[i] as DirectiveDef<any>;
|
const def = tView.data[i] as DirectiveDef<any>;
|
||||||
const directive = viewData[i];
|
const directive = viewData[i];
|
||||||
if (def.hostBindings) {
|
if (def.hostBindings) {
|
||||||
invokeHostBindingsInCreationMode(def, expando, directive, tNode, firstTemplatePass);
|
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) {
|
} else if (firstTemplatePass) {
|
||||||
expando.push(null);
|
expando.push(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setActiveHostElement(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function invokeHostBindingsInCreationMode(
|
export function invokeHostBindingsInCreationMode(
|
||||||
|
@ -914,9 +935,7 @@ export function invokeHostBindingsInCreationMode(
|
||||||
const previousExpandoLength = expando.length;
|
const previousExpandoLength = expando.length;
|
||||||
setCurrentDirectiveDef(def);
|
setCurrentDirectiveDef(def);
|
||||||
const elementIndex = tNode.index - HEADER_OFFSET;
|
const elementIndex = tNode.index - HEADER_OFFSET;
|
||||||
setActiveHost(directive, elementIndex);
|
|
||||||
def.hostBindings !(RenderFlags.Create, directive, elementIndex);
|
def.hostBindings !(RenderFlags.Create, directive, elementIndex);
|
||||||
setActiveHost(null);
|
|
||||||
setCurrentDirectiveDef(null);
|
setCurrentDirectiveDef(null);
|
||||||
// `hostBindings` function may or may not contain `allocHostVars` call
|
// `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
|
// (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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
||||||
import {TNode} from '../interfaces/node';
|
import {TNode, TNodeType} from '../interfaces/node';
|
||||||
import {PlayerFactory} from '../interfaces/player';
|
import {PlayerFactory} from '../interfaces/player';
|
||||||
import {FLAGS, HEADER_OFFSET, LViewFlags, RENDERER, RootContextFlags} from '../interfaces/view';
|
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 {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 {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 {NO_CHANGE} from '../tokens';
|
||||||
import {renderStringify} from '../util/misc_utils';
|
import {renderStringify} from '../util/misc_utils';
|
||||||
import {getRootContext} from '../util/view_traversal_utils';
|
import {getRootContext} from '../util/view_traversal_utils';
|
||||||
import {getTNode} from '../util/view_utils';
|
import {getTNode} from '../util/view_utils';
|
||||||
|
|
||||||
import {scheduleTick, setInputsForProperty} from './shared';
|
import {scheduleTick, setInputsForProperty} from './shared';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The contents of this file include the instructions for all styling-related
|
* The contents of this file include the instructions for all styling-related
|
||||||
* operations in Angular.
|
* operations in Angular.
|
||||||
|
@ -40,7 +45,6 @@ import {scheduleTick, setInputsForProperty} from './shared';
|
||||||
* - elementHostStylingApply
|
* - elementHostStylingApply
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates style and class binding properties on the element during creation mode.
|
* 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`
|
// components) then they will be applied at the end of the `elementEnd`
|
||||||
// instruction (because directives are created first before styling is
|
// instruction (because directives are created first before styling is
|
||||||
// executed for a new element).
|
// 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();
|
tNode.stylingTemplate = createEmptyStylingContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
const directive = getActiveHostContext();
|
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||||
|
|
||||||
// despite the binding being applied in a queue (below), the allocation
|
// despite the binding being applied in a queue (below), the allocation
|
||||||
// of the directive into the context happens right away. The reason for
|
// of the directive into the context happens right away. The reason for
|
||||||
// this is to retain the ordering of the directives (which is important
|
// this is to retain the ordering of the directives (which is important
|
||||||
// for the prioritization of bindings).
|
// for the prioritization of bindings).
|
||||||
allocateDirectiveIntoContext(tNode.stylingTemplate, directive);
|
allocateOrUpdateDirectiveIntoContext(tNode.stylingTemplate, directiveStylingIndex);
|
||||||
|
|
||||||
const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || [];
|
const fns = tNode.onElementCreationFns = tNode.onElementCreationFns || [];
|
||||||
fns.push(
|
fns.push(() => {
|
||||||
() => initElementStyling(
|
initElementStyling(
|
||||||
tNode, classBindingNames, styleBindingNames, styleSanitizer, directive));
|
tNode, classBindingNames, styleBindingNames, styleSanitizer, directiveStylingIndex);
|
||||||
|
registerHostDirective(tNode.stylingTemplate !, directiveStylingIndex);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initElementStyling(
|
function initElementStyling(
|
||||||
tNode: TNode, classBindingNames?: string[] | null, styleBindingNames?: string[] | null,
|
tNode: TNode, classBindingNames: string[] | null | undefined,
|
||||||
styleSanitizer?: StyleSanitizeFn | null, directive?: {} | null): void {
|
styleBindingNames: string[] | null | undefined,
|
||||||
|
styleSanitizer: StyleSanitizeFn | null | undefined, directiveStylingIndex: number): void {
|
||||||
updateContextWithBindings(
|
updateContextWithBindings(
|
||||||
tNode.stylingTemplate !, directive || null, classBindingNames, styleBindingNames,
|
tNode.stylingTemplate !, directiveStylingIndex, classBindingNames, styleBindingNames,
|
||||||
styleSanitizer);
|
styleSanitizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +169,10 @@ function initElementStyling(
|
||||||
export function elementStyleProp(
|
export function elementStyleProp(
|
||||||
index: number, styleIndex: number, value: string | number | String | PlayerFactory | null,
|
index: number, styleIndex: number, value: string | number | String | PlayerFactory | null,
|
||||||
suffix?: string | null, forceOverride?: boolean): void {
|
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(
|
export function elementHostStyleProp(
|
||||||
styleIndex: number, value: string | number | String | PlayerFactory | null,
|
styleIndex: number, value: string | number | String | PlayerFactory | null,
|
||||||
suffix?: string | null, forceOverride?: boolean): void {
|
suffix?: string | null, forceOverride?: boolean): void {
|
||||||
elementStylePropInternal(
|
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||||
getActiveHostContext() !, getActiveHostElementIndex() !, styleIndex, value, suffix,
|
const hostElementIndex = getSelectedIndex();
|
||||||
forceOverride);
|
|
||||||
|
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(
|
function resolveStylePropValue(
|
||||||
directive: {} | null, index: number, styleIndex: number,
|
value: string | number | String | PlayerFactory | null, suffix: string | null | undefined) {
|
||||||
value: string | number | String | PlayerFactory | null, suffix?: string | null,
|
|
||||||
forceOverride?: boolean): void {
|
|
||||||
let valueToAdd: string|null = null;
|
let valueToAdd: string|null = null;
|
||||||
if (value !== null) {
|
if (value !== null) {
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
|
@ -214,9 +231,7 @@ function elementStylePropInternal(
|
||||||
valueToAdd = value as any as string;
|
valueToAdd = value as any as string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateElementStyleProp(
|
return valueToAdd;
|
||||||
getStylingContext(index + HEADER_OFFSET, getLView()), styleIndex, valueToAdd, directive,
|
|
||||||
forceOverride);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -241,7 +256,12 @@ function elementStylePropInternal(
|
||||||
export function elementClassProp(
|
export function elementClassProp(
|
||||||
index: number, classIndex: number, value: boolean | PlayerFactory,
|
index: number, classIndex: number, value: boolean | PlayerFactory,
|
||||||
forceOverride?: boolean): void {
|
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(
|
export function elementHostClassProp(
|
||||||
classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void {
|
classIndex: number, value: boolean | PlayerFactory, forceOverride?: boolean): void {
|
||||||
elementClassPropInternal(
|
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||||
getActiveHostContext() !, getActiveHostElementIndex() !, classIndex, value, forceOverride);
|
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) ?
|
const input = (value instanceof BoundPlayerFactory) ?
|
||||||
(value as BoundPlayerFactory<boolean|null>) :
|
(value as BoundPlayerFactory<boolean|null>) :
|
||||||
booleanOrNull(value);
|
booleanOrNull(value);
|
||||||
updateElementClassProp(
|
|
||||||
getStylingContext(index + HEADER_OFFSET, getLView()), classIndex, input, directive,
|
const args: ParamsOf<typeof updateElementClassProp> =
|
||||||
forceOverride);
|
[stylingContext, classIndex, input, directiveStylingIndex, forceOverride];
|
||||||
|
enqueueHostInstruction(stylingContext, directiveStylingIndex, updateElementClassProp, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function booleanOrNull(value: any): boolean|null {
|
function booleanOrNull(value: any): boolean|null {
|
||||||
|
@ -309,7 +329,30 @@ function booleanOrNull(value: any): boolean|null {
|
||||||
export function elementStylingMap(
|
export function elementStylingMap(
|
||||||
index: number, classes: {[key: string]: any} | string | NO_CHANGE | null,
|
index: number, classes: {[key: string]: any} | string | NO_CHANGE | null,
|
||||||
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
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(
|
export function elementHostStylingMap(
|
||||||
classes: {[key: string]: any} | string | NO_CHANGE | null,
|
classes: {[key: string]: any} | string | NO_CHANGE | null,
|
||||||
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
styles?: {[styleName: string]: any} | NO_CHANGE | null): void {
|
||||||
elementStylingMapInternal(
|
const directiveStylingIndex = getActiveDirectiveStylingIndex();
|
||||||
getActiveHostContext() !, getActiveHostElementIndex() !, classes, styles);
|
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 lView = getLView();
|
||||||
const tNode = getTNode(index, lView);
|
const stylingContext = getStylingContext(hostElementIndex + HEADER_OFFSET, lView);
|
||||||
const stylingContext = getStylingContext(index + HEADER_OFFSET, lView);
|
|
||||||
|
|
||||||
// inputs are only evaluated from a template binding into a directive, therefore,
|
const args: ParamsOf<typeof updateStylingMap> =
|
||||||
// there should not be a situation where a directive host bindings function
|
[stylingContext, classes, styles, directiveStylingIndex];
|
||||||
// evaluates the inputs (this should only happen in the template function)
|
enqueueHostInstruction(stylingContext, directiveStylingIndex, updateStylingMap, args);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -387,7 +406,7 @@ function elementStylingMapInternal(
|
||||||
* @publicApi
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export function elementStylingApply(index: number): void {
|
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
|
* @publicApi
|
||||||
*/
|
*/
|
||||||
export function elementHostStylingApply(): void {
|
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 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 isFirstRender = (lView[FLAGS] & LViewFlags.FirstLViewPass) !== 0;
|
||||||
|
const stylingContext = getStylingContext(index + HEADER_OFFSET, lView);
|
||||||
const totalPlayersQueued = renderStyling(
|
const totalPlayersQueued = renderStyling(
|
||||||
getStylingContext(index + HEADER_OFFSET, lView), lView[RENDERER], lView, isFirstRender, null,
|
stylingContext, renderer, lView, isFirstRender, null, null, directiveStylingIndex);
|
||||||
null, directive);
|
|
||||||
if (totalPlayersQueued > 0) {
|
if (totalPlayersQueued > 0) {
|
||||||
const rootContext = getRootContext(lView);
|
const rootContext = getRootContext(lView);
|
||||||
scheduleTick(rootContext, RootContextFlags.FlushPlayers);
|
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;
|
[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
|
* Location of animation context (which contains the active players) for this element styling
|
||||||
* context.
|
* context.
|
||||||
|
@ -316,6 +331,66 @@ export interface StylingContext extends
|
||||||
[StylingIndex.PlayerContext]: PlayerContext|null;
|
[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
|
* 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
|
* 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).
|
* 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> {
|
export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|StyleSanitizeFn> {
|
||||||
[DirectiveRegistryValuesIndex.DirectiveValueOffset]: null;
|
|
||||||
[DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset]: number;
|
[DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset]: number;
|
||||||
[DirectiveRegistryValuesIndex.DirtyFlagOffset]: boolean;
|
|
||||||
[DirectiveRegistryValuesIndex.StyleSanitizerOffset]: StyleSanitizeFn|null;
|
[DirectiveRegistryValuesIndex.StyleSanitizerOffset]: StyleSanitizeFn|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,11 +595,9 @@ export interface DirectiveRegistryValues extends Array<null|{}|boolean|number|St
|
||||||
* that are housed inside of [DirectiveRegistryValues].
|
* that are housed inside of [DirectiveRegistryValues].
|
||||||
*/
|
*/
|
||||||
export const enum DirectiveRegistryValuesIndex {
|
export const enum DirectiveRegistryValuesIndex {
|
||||||
DirectiveValueOffset = 0,
|
SinglePropValuesIndexOffset = 0,
|
||||||
SinglePropValuesIndexOffset = 1,
|
StyleSanitizerOffset = 1,
|
||||||
DirtyFlagOffset = 2,
|
Size = 2
|
||||||
StyleSanitizerOffset = 3,
|
|
||||||
Size = 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -678,9 +749,10 @@ export const enum StylingIndex {
|
||||||
CachedMultiStyles = 7,
|
CachedMultiStyles = 7,
|
||||||
// Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue
|
// Multi and single entries are stored in `StylingContext` as: Flag; PropertyName; PropertyValue
|
||||||
// Position of where the initial styles are stored in the styling context
|
// 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
|
// Location of single (prop) value entries are stored within the context
|
||||||
SingleStylesStartPosition = 9,
|
SingleStylesStartPosition = 10,
|
||||||
FlagsOffset = 0,
|
FlagsOffset = 0,
|
||||||
PropertyOffset = 1,
|
PropertyOffset = 1,
|
||||||
ValueOffset = 2,
|
ValueOffset = 2,
|
||||||
|
@ -705,3 +777,13 @@ export const enum DirectiveOwnerAndPlayerBuilderIndex {
|
||||||
BitCountSize = 16,
|
BitCountSize = 16,
|
||||||
BitMask = 0b1111111111111111
|
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;
|
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.
|
* Position depth (with respect from leaf to root) in a directive sub-class inheritance chain.
|
||||||
*
|
|
||||||
* @param host the directive/component instance
|
|
||||||
* @param index the element index value for the host element where the directive/component instance
|
|
||||||
* lives
|
|
||||||
*/
|
*/
|
||||||
export function setActiveHost(host: {} | null, index: number | null = null) {
|
let activeDirectiveSuperClassDepthPosition = 0;
|
||||||
activeHostContext = host;
|
|
||||||
activeHostElementIndex = index;
|
/**
|
||||||
|
* 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 {AttributeMarker, TAttributes} from '../interfaces/node';
|
||||||
import {BindingStore, BindingType, Player, PlayerBuilder, PlayerFactory, PlayerIndex} from '../interfaces/player';
|
import {BindingStore, BindingType, Player, PlayerBuilder, PlayerFactory, PlayerIndex} from '../interfaces/player';
|
||||||
import {RElement, Renderer3, RendererStyleFlags3, isProceduralRenderer} from '../interfaces/renderer';
|
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 {LView, RootContext} from '../interfaces/view';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
import {getRootContext} from '../util/view_traversal_utils';
|
import {getRootContext} from '../util/view_traversal_utils';
|
||||||
|
|
||||||
|
import {allowFlush as allowHostInstructionsQueueFlush, flushQueue as flushHostInstructionsQueue} from './host_instructions_queue';
|
||||||
import {BoundPlayerFactory} from './player_factory';
|
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.
|
* Creates a new StylingContext an fills it with the provided static styling attribute values.
|
||||||
*/
|
*/
|
||||||
export function initializeStaticContext(
|
export function initializeStaticContext(
|
||||||
attrs: TAttributes, stylingStartIndex: number, directiveRef?: any | null): StylingContext {
|
attrs: TAttributes, stylingStartIndex: number, directiveIndex: number = 0): StylingContext {
|
||||||
const context = createEmptyStylingContext();
|
const context = createEmptyStylingContext();
|
||||||
patchContextWithStaticAttrs(context, attrs, stylingStartIndex, directiveRef);
|
patchContextWithStaticAttrs(context, attrs, stylingStartIndex, directiveIndex);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,25 +57,14 @@ export function initializeStaticContext(
|
||||||
* assigned to the context
|
* assigned to the context
|
||||||
* @param attrsStylingStartIndex what index to start iterating within the
|
* @param attrsStylingStartIndex what index to start iterating within the
|
||||||
* provided `attrs` array to start reading style and class values
|
* 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(
|
export function patchContextWithStaticAttrs(
|
||||||
context: StylingContext, attrs: TAttributes, attrsStylingStartIndex: number,
|
context: StylingContext, attrs: TAttributes, attrsStylingStartIndex: number,
|
||||||
directiveRef?: any | null): void {
|
directiveIndex: number): void {
|
||||||
// this means the context has already been set and instantiated
|
// this means the context has already been set and instantiated
|
||||||
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
||||||
|
|
||||||
// If the styling context has already been patched with the given directive's bindings,
|
allocateOrUpdateDirectiveIntoContext(context, directiveIndex);
|
||||||
// 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;
|
|
||||||
|
|
||||||
let initialClasses: InitialStylingValues|null = null;
|
let initialClasses: InitialStylingValues|null = null;
|
||||||
let initialStyles: InitialStylingValues|null = null;
|
let initialStyles: InitialStylingValues|null = null;
|
||||||
|
@ -199,7 +188,6 @@ export function allowNewBindingsForStylingContext(context: StylingContext): bool
|
||||||
* reference the provided directive.
|
* reference the provided directive.
|
||||||
*
|
*
|
||||||
* @param context the existing styling context
|
* @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 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 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
|
* @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.
|
* instance will only be active if and when the directive updates the bindings that it owns.
|
||||||
*/
|
*/
|
||||||
export function updateContextWithBindings(
|
export function updateContextWithBindings(
|
||||||
context: StylingContext, directiveRef: any | null, classBindingNames?: string[] | null,
|
context: StylingContext, directiveIndex: number, classBindingNames?: string[] | null,
|
||||||
styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null) {
|
styleBindingNames?: string[] | null, styleSanitizer?: StyleSanitizeFn | null) {
|
||||||
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
if (context[StylingIndex.MasterFlagPosition] & StylingFlags.BindingAllocationLocked) return;
|
||||||
|
|
||||||
// this means the context has already been patched with the directive's bindings
|
// this means the context has already been patched with the directive's bindings
|
||||||
const directiveIndex = findOrPatchDirectiveIntoRegistry(context, directiveRef, styleSanitizer);
|
const isNewDirective =
|
||||||
if (directiveIndex === -1) {
|
findOrPatchDirectiveIntoRegistry(context, directiveIndex, false, styleSanitizer);
|
||||||
|
if (!isNewDirective) {
|
||||||
// this means the directive has already been patched in ... No point in doing anything
|
// this means the directive has already been patched in ... No point in doing anything
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -470,46 +459,22 @@ export function updateContextWithBindings(
|
||||||
* Searches through the existing registry of directives
|
* Searches through the existing registry of directives
|
||||||
*/
|
*/
|
||||||
export function findOrPatchDirectiveIntoRegistry(
|
export function findOrPatchDirectiveIntoRegistry(
|
||||||
context: StylingContext, directiveRef: any, styleSanitizer?: StyleSanitizeFn | null) {
|
context: StylingContext, directiveIndex: number, staticModeOnly: boolean,
|
||||||
const directiveRefs = context[StylingIndex.DirectiveRegistryPosition];
|
styleSanitizer?: StyleSanitizeFn | null): boolean {
|
||||||
const nextOffsetInsertionIndex = context[StylingIndex.SinglePropOffsetPositions].length;
|
const directiveRegistry = context[StylingIndex.DirectiveRegistryPosition];
|
||||||
|
const index = directiveIndex * DirectiveRegistryValuesIndex.Size;
|
||||||
|
const singlePropStartPosition = index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||||
|
|
||||||
let directiveIndex: number;
|
// this means that the directive has already been registered into the registry
|
||||||
let detectedIndex = getDirectiveRegistryValuesIndexOf(directiveRefs, directiveRef);
|
if (index < directiveRegistry.length &&
|
||||||
|
(directiveRegistry[singlePropStartPosition] as number) >= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (detectedIndex === -1) {
|
const singlePropsStartIndex =
|
||||||
detectedIndex = directiveRefs.length;
|
staticModeOnly ? -1 : context[StylingIndex.SinglePropOffsetPositions].length;
|
||||||
directiveIndex = directiveRefs.length / DirectiveRegistryValuesIndex.Size;
|
allocateOrUpdateDirectiveIntoContext(
|
||||||
|
context, directiveIndex, singlePropsStartIndex, styleSanitizer);
|
||||||
allocateDirectiveIntoContext(context, directiveRef);
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMatchingBindingIndex(
|
function getMatchingBindingIndex(
|
||||||
|
@ -543,18 +508,13 @@ function getMatchingBindingIndex(
|
||||||
* newly provided style values.
|
* newly provided style values.
|
||||||
* @param classesInput The key/value map of CSS class names that will be used for the update.
|
* @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 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(
|
export function updateStylingMap(
|
||||||
context: StylingContext, classesInput: {[key: string]: any} | string |
|
context: StylingContext, classesInput: {[key: string]: any} | string |
|
||||||
BoundPlayerFactory<null|string|{[key: string]: any}>| null,
|
BoundPlayerFactory<null|string|{[key: string]: any}>| null,
|
||||||
stylesInput?: {[key: string]: any} | BoundPlayerFactory<null|{[key: string]: any}>| null,
|
stylesInput?: {[key: string]: any} | BoundPlayerFactory<null|{[key: string]: any}>| null,
|
||||||
directiveRef?: any): void {
|
directiveIndex: number = 0): void {
|
||||||
const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
ngDevMode && assertValidDirectiveIndex(context, directiveIndex);
|
||||||
|
|
||||||
classesInput = classesInput || null;
|
classesInput = classesInput || null;
|
||||||
stylesInput = stylesInput || null;
|
stylesInput = stylesInput || null;
|
||||||
const ignoreAllClassUpdates = isMultiValueCacheHit(context, true, directiveIndex, classesInput);
|
const ignoreAllClassUpdates = isMultiValueCacheHit(context, true, directiveIndex, classesInput);
|
||||||
|
@ -887,7 +847,6 @@ function patchStylingMapIntoContext(
|
||||||
|
|
||||||
if (dirty) {
|
if (dirty) {
|
||||||
setContextDirty(context, true);
|
setContextDirty(context, true);
|
||||||
setDirectiveDirty(context, directiveIndex, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalNewAllocatedSlots;
|
return totalNewAllocatedSlots;
|
||||||
|
@ -901,18 +860,14 @@ function patchStylingMapIntoContext(
|
||||||
* newly provided class value.
|
* newly provided class value.
|
||||||
* @param offset The index of the CSS class which is being updated.
|
* @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 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
|
* @param forceOverride whether or not to skip all directive prioritization
|
||||||
* and just apply the value regardless.
|
* and just apply the value regardless.
|
||||||
*/
|
*/
|
||||||
export function updateClassProp(
|
export function updateClassProp(
|
||||||
context: StylingContext, offset: number,
|
context: StylingContext, offset: number,
|
||||||
input: boolean | BoundPlayerFactory<boolean|null>| null, directiveRef?: any,
|
input: boolean | BoundPlayerFactory<boolean|null>| null, directiveIndex: number = 0,
|
||||||
forceOverride?: boolean): void {
|
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.
|
* newly provided style value.
|
||||||
* @param offset The index of the property which is being updated.
|
* @param offset The index of the property which is being updated.
|
||||||
* @param value The CSS style value that will be assigned
|
* @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
|
* @param forceOverride whether or not to skip all directive prioritization
|
||||||
* and just apply the value regardless.
|
* and just apply the value regardless.
|
||||||
*/
|
*/
|
||||||
export function updateStyleProp(
|
export function updateStyleProp(
|
||||||
context: StylingContext, offset: number,
|
context: StylingContext, offset: number,
|
||||||
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>, directiveRef?: any,
|
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>,
|
||||||
forceOverride?: boolean): void {
|
directiveIndex: number = 0, forceOverride?: boolean): void {
|
||||||
updateSingleStylingValue(context, offset, input, false, directiveRef, forceOverride);
|
updateSingleStylingValue(context, offset, input, false, directiveIndex, forceOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSingleStylingValue(
|
function updateSingleStylingValue(
|
||||||
context: StylingContext, offset: number,
|
context: StylingContext, offset: number,
|
||||||
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>, isClassBased: boolean,
|
input: string | boolean | null | BoundPlayerFactory<string|boolean|null>, isClassBased: boolean,
|
||||||
directiveRef: any, forceOverride?: boolean): void {
|
directiveIndex: number, forceOverride?: boolean): void {
|
||||||
const directiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
ngDevMode && assertValidDirectiveIndex(context, directiveIndex);
|
||||||
const singleIndex = getSinglePropIndexValue(context, directiveIndex, offset, isClassBased);
|
const singleIndex = getSinglePropIndexValue(context, directiveIndex, offset, isClassBased);
|
||||||
const currValue = getValue(context, singleIndex);
|
const currValue = getValue(context, singleIndex);
|
||||||
const currFlag = getPointers(context, singleIndex);
|
const currFlag = getPointers(context, singleIndex);
|
||||||
|
@ -1001,7 +952,6 @@ function updateSingleStylingValue(
|
||||||
|
|
||||||
setDirty(context, indexForMulti, multiDirty);
|
setDirty(context, indexForMulti, multiDirty);
|
||||||
setDirty(context, singleIndex, singleDirty);
|
setDirty(context, singleIndex, singleDirty);
|
||||||
setDirectiveDirty(context, directiveIndex, true);
|
|
||||||
setContextDirty(context, true);
|
setContextDirty(context, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,120 +979,128 @@ function updateSingleStylingValue(
|
||||||
* to this key/value map instead of being renderered via the renderer.
|
* to this key/value map instead of being renderered via the renderer.
|
||||||
* @param stylesStore if provided, the updated style values will be applied
|
* @param stylesStore if provided, the updated style values will be applied
|
||||||
* to this key/value map instead of being renderered via the renderer.
|
* 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)
|
* @returns number the total amount of players that got queued for animation (if any)
|
||||||
*/
|
*/
|
||||||
export function renderStyling(
|
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,
|
isFirstRender: boolean, classesStore?: BindingStore | null, stylesStore?: BindingStore | null,
|
||||||
directiveRef?: any): number {
|
directiveIndex: number = 0): number {
|
||||||
let totalPlayersQueued = 0;
|
let totalPlayersQueued = 0;
|
||||||
const targetDirectiveIndex = getDirectiveIndexFromRegistry(context, directiveRef || null);
|
|
||||||
|
|
||||||
if (isContextDirty(context) && isDirectiveDirty(context, targetDirectiveIndex)) {
|
// this prevents multiple attempts to render style/class values on
|
||||||
const flushPlayerBuilders: any =
|
// the same element...
|
||||||
context[StylingIndex.MasterFlagPosition] & StylingFlags.PlayerBuildersDirty;
|
if (allowHostInstructionsQueueFlush(context, directiveIndex)) {
|
||||||
const native = context[StylingIndex.ElementPosition] !;
|
// all styling instructions present within any hostBindings functions
|
||||||
const multiStartIndex = getMultiStylesStartIndex(context);
|
// 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;
|
if (isContextDirty(context)) {
|
||||||
for (let i = StylingIndex.SingleStylesStartPosition; i < context.length;
|
// this is here to prevent things like <ng-container [style] [class]>...</ng-container>
|
||||||
i += StylingIndex.Size) {
|
// or if there are any host style or class bindings present in a directive set on
|
||||||
// there is no point in rendering styles that have not changed on screen
|
// a container node
|
||||||
if (isDirty(context, i)) {
|
const native = context[StylingIndex.ElementPosition] !as HTMLElement;
|
||||||
const flag = getPointers(context, i);
|
|
||||||
const directiveIndex = getDirectiveIndexFromEntry(context, i);
|
|
||||||
if (targetDirectiveIndex !== directiveIndex) {
|
|
||||||
stillDirty = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prop = getProp(context, i);
|
const flushPlayerBuilders: any =
|
||||||
const value = getValue(context, i);
|
context[StylingIndex.MasterFlagPosition] & StylingFlags.PlayerBuildersDirty;
|
||||||
const styleSanitizer =
|
const multiStartIndex = getMultiStylesStartIndex(context);
|
||||||
(flag & StylingFlags.Sanitize) ? getStyleSanitizer(context, directiveIndex) : null;
|
|
||||||
const playerBuilder = getPlayerBuilder(context, i);
|
|
||||||
const isClassBased = flag & StylingFlags.Class ? true : false;
|
|
||||||
const isInSingleRegion = i < multiStartIndex;
|
|
||||||
|
|
||||||
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
|
let valueToApply: string|boolean|null = 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// VALUE DEFER CASE 2: Use the initial value if all else fails (is falsy)
|
// VALUE DEFER CASE 1: Use a multi value instead of a null single value
|
||||||
// the initial value will always be a string or null,
|
// this check implies that a single value was removed and we
|
||||||
// therefore we can safely adopt it in case there's nothing else
|
// should now defer to a multi value and use that (if set).
|
||||||
// note that this should always be a falsy check since `false` is used
|
if (isInSingleRegion && !valueExists(valueToApply, isClassBased)) {
|
||||||
// for both class and style comparisons (styles can't be false and false
|
// single values ALWAYS have a reference to a multi index
|
||||||
// classes are turned off and should therefore defer to their initial values)
|
const multiIndex = getMultiOrSingleIndex(flag);
|
||||||
// Note that we ignore class-based deferals because otherwise a class can never
|
valueToApply = getValue(context, multiIndex);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
// if the first render is true then we do not want to start applying falsy
|
||||||
const rootContext =
|
// values to the DOM element's styling. Otherwise then we know there has
|
||||||
Array.isArray(rootOrView) ? getRootContext(rootOrView) : rootOrView as RootContext;
|
// been a change and even if it's falsy then it's removing something that
|
||||||
const playerContext = getPlayerContext(context) !;
|
// was truthy before.
|
||||||
const playersStartIndex = playerContext[PlayerIndex.NonBuilderPlayersStart];
|
const doApplyValue = renderer && (isFirstRender ? valueToApply : true);
|
||||||
for (let i = PlayerIndex.PlayerBuildersStartPosition; i < playersStartIndex;
|
if (doApplyValue) {
|
||||||
i += PlayerIndex.PlayerAndPlayerBuildersTupleSize) {
|
if (isClassBased) {
|
||||||
const builder = playerContext[i] as ClassAndStylePlayerBuilder<any>| null;
|
setClass(
|
||||||
const playerInsertionIndex = i + PlayerIndex.PlayerOffsetPosition;
|
native, prop, valueToApply ? true : false, renderer !, classesStore,
|
||||||
const oldPlayer = playerContext[playerInsertionIndex] as Player | null;
|
playerBuilder);
|
||||||
if (builder) {
|
} else {
|
||||||
const player = builder.buildPlayer(oldPlayer, isFirstRender);
|
setStyle(
|
||||||
if (player !== undefined) {
|
native, prop, valueToApply as string | null, renderer !, styleSanitizer,
|
||||||
if (player != null) {
|
stylesStore, playerBuilder);
|
||||||
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
|
setDirty(context, i, false);
|
||||||
// player
|
|
||||||
oldPlayer.destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setContextPlayersDirty(context, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setDirectiveDirty(context, targetDirectiveIndex, false);
|
if (flushPlayerBuilders) {
|
||||||
setContextDirty(context, stillDirty);
|
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;
|
return totalPlayersQueued;
|
||||||
|
@ -1622,43 +1580,6 @@ export function getDirectiveIndexFromEntry(context: StylingContext, index: numbe
|
||||||
return value & DirectiveOwnerAndPlayerBuilderIndex.BitMask;
|
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 {
|
function getInitialStylingValuesIndexOf(keyValues: InitialStylingValues, key: string): number {
|
||||||
for (let i = InitialStylingValuesIndex.KeyValueStartPosition; i < keyValues.length;
|
for (let i = InitialStylingValuesIndex.KeyValueStartPosition; i < keyValues.length;
|
||||||
i += InitialStylingValuesIndex.Size) {
|
i += InitialStylingValuesIndex.Size) {
|
||||||
|
@ -1724,21 +1645,6 @@ function getStyleSanitizer(context: StylingContext, directiveIndex: number): Sty
|
||||||
return value as StyleSanitizeFn | null;
|
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(
|
function allowValueChange(
|
||||||
currentValue: string | boolean | null, newValue: string | boolean | null,
|
currentValue: string | boolean | null, newValue: string | boolean | null,
|
||||||
currentDirectiveOwner: number, newDirectiveOwner: number) {
|
currentDirectiveOwner: number, newDirectiveOwner: number) {
|
||||||
|
@ -1994,3 +1900,12 @@ function addOrUpdateStaticStyle(
|
||||||
staticStyles[index + InitialStylingValuesIndex.DirectiveOwnerOffset] = directiveOwnerIndex;
|
staticStyles[index + InitialStylingValuesIndex.DirectiveOwnerOffset] = directiveOwnerIndex;
|
||||||
return index;
|
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 {getTNode, isStylingContext} from '../util/view_utils';
|
||||||
|
|
||||||
import {CorePlayerHandler} from './core_player_handler';
|
import {CorePlayerHandler} from './core_player_handler';
|
||||||
|
import {DEFAULT_TEMPLATE_DIRECTIVE_INDEX} from './shared';
|
||||||
|
|
||||||
export const ANIMATION_PROP_PREFIX = '@';
|
export const ANIMATION_PROP_PREFIX = '@';
|
||||||
|
|
||||||
|
@ -35,12 +36,13 @@ export function createEmptyStylingContext(
|
||||||
[0, 0], // SinglePropOffsets
|
[0, 0], // SinglePropOffsets
|
||||||
[0], // CachedMultiClassValue
|
[0], // CachedMultiClassValue
|
||||||
[0], // CachedMultiStyleValue
|
[0], // CachedMultiStyleValue
|
||||||
|
null, // HostBuffer
|
||||||
null, // PlayerContext
|
null, // PlayerContext
|
||||||
];
|
];
|
||||||
|
|
||||||
// whenever a context is created there is always a `null` directive
|
// whenever a context is created there is always a `null` directive
|
||||||
// that is registered (which is a placeholder for the "template").
|
// that is registered (which is a placeholder for the "template").
|
||||||
allocateDirectiveIntoContext(context, null);
|
allocateOrUpdateDirectiveIntoContext(context, DEFAULT_TEMPLATE_DIRECTIVE_INDEX);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,25 +62,28 @@ export function createEmptyStylingContext(
|
||||||
* @param directiveRef the directive that will be allocated into the context
|
* @param directiveRef the directive that will be allocated into the context
|
||||||
* @returns the index where the directive was inserted into
|
* @returns the index where the directive was inserted into
|
||||||
*/
|
*/
|
||||||
export function allocateDirectiveIntoContext(
|
export function allocateOrUpdateDirectiveIntoContext(
|
||||||
context: StylingContext, directiveRef: any | null): number {
|
context: StylingContext, directiveIndex: number, singlePropValuesIndex: number = -1,
|
||||||
// this is a new directive which we have not seen yet.
|
styleSanitizer?: StyleSanitizeFn | null | undefined): void {
|
||||||
const dirs = context[StylingIndex.DirectiveRegistryPosition];
|
const directiveRegistry = context[StylingIndex.DirectiveRegistryPosition];
|
||||||
const i = dirs.length;
|
|
||||||
|
|
||||||
|
const index = directiveIndex * DirectiveRegistryValuesIndex.Size;
|
||||||
// we preemptively make space into the directives array and then
|
// we preemptively make space into the directives array and then
|
||||||
// assign values slot-by-slot to ensure that if the directive ordering
|
// assign values slot-by-slot to ensure that if the directive ordering
|
||||||
// changes then it will still function
|
// changes then it will still function
|
||||||
dirs.push(null, null, null, null);
|
const limit = index + DirectiveRegistryValuesIndex.Size;
|
||||||
dirs[i + DirectiveRegistryValuesIndex.DirectiveValueOffset] = directiveRef;
|
for (let i = directiveRegistry.length; i < limit; i += DirectiveRegistryValuesIndex.Size) {
|
||||||
dirs[i + DirectiveRegistryValuesIndex.DirtyFlagOffset] = false;
|
// -1 is used to signal that the directive has been allocated, but
|
||||||
dirs[i + DirectiveRegistryValuesIndex.StyleSanitizerOffset] = null;
|
// 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
|
const propValuesStartPosition = index + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset;
|
||||||
// no actual style or class bindings have been registered yet...
|
if (singlePropValuesIndex >= 0 && directiveRegistry[propValuesStartPosition] === -1) {
|
||||||
dirs[i + DirectiveRegistryValuesIndex.SinglePropValuesIndexOffset] = -1;
|
directiveRegistry[propValuesStartPosition] = singlePropValuesIndex;
|
||||||
|
directiveRegistry[index + DirectiveRegistryValuesIndex.StyleSanitizerOffset] =
|
||||||
return i;
|
styleSanitizer || null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,12 +11,12 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
import {ivyEnabled, onlyInIvy} from '@angular/private/testing';
|
||||||
|
|
||||||
describe('acceptance integration tests', () => {
|
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', () => {
|
.it('should render host bindings on the root component', () => {
|
||||||
@Component({template: '...'})
|
@Component({template: '...'})
|
||||||
class MyApp {
|
class MyApp {
|
||||||
@HostBinding('style') public myStylesExp = {};
|
@HostBinding('style') myStylesExp = {};
|
||||||
@HostBinding('class') public myClassesExp = {};
|
@HostBinding('class') myClassesExp = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
TestBed.configureTestingModule({declarations: [MyApp]});
|
TestBed.configureTestingModule({declarations: [MyApp]});
|
||||||
|
@ -153,4 +153,166 @@ describe('acceptance integration tests', () => {
|
||||||
expect(element.style.width).toEqual('300px');
|
expect(element.style.width).toEqual('300px');
|
||||||
expect(element.classList.contains('abc')).toBeFalsy();
|
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": "DECLARATION_VIEW"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DEFAULT_TEMPLATE_DIRECTIVE_INDEX"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DepComponent"
|
"name": "DepComponent"
|
||||||
},
|
},
|
||||||
|
@ -158,6 +161,9 @@
|
||||||
{
|
{
|
||||||
"name": "_renderCompCount"
|
"name": "_renderCompCount"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_selectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "addComponentLogic"
|
"name": "addComponentLogic"
|
||||||
},
|
},
|
||||||
|
@ -171,7 +177,7 @@
|
||||||
"name": "allocStylingContext"
|
"name": "allocStylingContext"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "allocateDirectiveIntoContext"
|
"name": "allocateOrUpdateDirectiveIntoContext"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "allowValueChange"
|
"name": "allowValueChange"
|
||||||
|
@ -338,9 +344,6 @@
|
||||||
{
|
{
|
||||||
"name": "getDirectiveDef"
|
"name": "getDirectiveDef"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getDirectiveRegistryValuesIndexOf"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getElementDepthCount"
|
"name": "getElementDepthCount"
|
||||||
},
|
},
|
||||||
|
@ -449,6 +452,9 @@
|
||||||
{
|
{
|
||||||
"name": "increaseElementDepthCount"
|
"name": "increaseElementDepthCount"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "incrementActiveDirectiveId"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "initNodeFlags"
|
"name": "initNodeFlags"
|
||||||
},
|
},
|
||||||
|
@ -627,7 +633,7 @@
|
||||||
"name": "saveResolvedLocalsInData"
|
"name": "saveResolvedLocalsInData"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setActiveHost"
|
"name": "setActiveHostElement"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setBindingRoot"
|
"name": "setBindingRoot"
|
||||||
|
@ -668,6 +674,9 @@
|
||||||
{
|
{
|
||||||
"name": "setPreviousOrParentTNode"
|
"name": "setPreviousOrParentTNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setSelectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setStyle"
|
"name": "setStyle"
|
||||||
},
|
},
|
||||||
|
|
|
@ -134,6 +134,9 @@
|
||||||
{
|
{
|
||||||
"name": "_renderCompCount"
|
"name": "_renderCompCount"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_selectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "addToViewTree"
|
"name": "addToViewTree"
|
||||||
},
|
},
|
||||||
|
@ -323,6 +326,9 @@
|
||||||
{
|
{
|
||||||
"name": "includeViewProviders"
|
"name": "includeViewProviders"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "incrementActiveDirectiveId"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "initNodeFlags"
|
"name": "initNodeFlags"
|
||||||
},
|
},
|
||||||
|
@ -435,7 +441,7 @@
|
||||||
"name": "resetPreOrderHookFlags"
|
"name": "resetPreOrderHookFlags"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setActiveHost"
|
"name": "setActiveHostElement"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setBindingRoot"
|
"name": "setBindingRoot"
|
||||||
|
@ -464,6 +470,9 @@
|
||||||
{
|
{
|
||||||
"name": "setPreviousOrParentTNode"
|
"name": "setPreviousOrParentTNode"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setSelectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setStyle"
|
"name": "setStyle"
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
{
|
{
|
||||||
"name": "DECLARATION_VIEW"
|
"name": "DECLARATION_VIEW"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DEFAULT_TEMPLATE_DIRECTIVE_INDEX"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DefaultIterableDiffer"
|
"name": "DefaultIterableDiffer"
|
||||||
},
|
},
|
||||||
|
@ -371,6 +374,9 @@
|
||||||
{
|
{
|
||||||
"name": "_renderCompCount"
|
"name": "_renderCompCount"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "_selectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "_symbolIterator"
|
"name": "_symbolIterator"
|
||||||
},
|
},
|
||||||
|
@ -399,7 +405,10 @@
|
||||||
"name": "allocStylingContext"
|
"name": "allocStylingContext"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "allocateDirectiveIntoContext"
|
"name": "allocateOrUpdateDirectiveIntoContext"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "allowFlush"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "allowValueChange"
|
"name": "allowValueChange"
|
||||||
|
@ -572,9 +581,6 @@
|
||||||
{
|
{
|
||||||
"name": "elementClassProp"
|
"name": "elementClassProp"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "elementClassPropInternal"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "elementCreate"
|
"name": "elementCreate"
|
||||||
},
|
},
|
||||||
|
@ -644,6 +650,9 @@
|
||||||
{
|
{
|
||||||
"name": "findViaComponent"
|
"name": "findViaComponent"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "flushQueue"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "forwardRef"
|
"name": "forwardRef"
|
||||||
},
|
},
|
||||||
|
@ -698,12 +707,6 @@
|
||||||
{
|
{
|
||||||
"name": "getDirectiveIndexFromEntry"
|
"name": "getDirectiveIndexFromEntry"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getDirectiveIndexFromRegistry"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "getDirectiveRegistryValuesIndexOf"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getElementDepthCount"
|
"name": "getElementDepthCount"
|
||||||
},
|
},
|
||||||
|
@ -755,9 +758,6 @@
|
||||||
{
|
{
|
||||||
"name": "getMatchingBindingIndex"
|
"name": "getMatchingBindingIndex"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getMultiClassesStartIndex"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getMultiOrSingleIndex"
|
"name": "getMultiOrSingleIndex"
|
||||||
},
|
},
|
||||||
|
@ -908,6 +908,9 @@
|
||||||
{
|
{
|
||||||
"name": "increaseElementDepthCount"
|
"name": "increaseElementDepthCount"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "incrementActiveDirectiveId"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "initElementStyling"
|
"name": "initElementStyling"
|
||||||
},
|
},
|
||||||
|
@ -983,9 +986,6 @@
|
||||||
{
|
{
|
||||||
"name": "isDifferent"
|
"name": "isDifferent"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "isDirectiveDirty"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "isDirty"
|
"name": "isDirty"
|
||||||
},
|
},
|
||||||
|
@ -1224,7 +1224,7 @@
|
||||||
"name": "select"
|
"name": "select"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setActiveHost"
|
"name": "setActiveHostElement"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setBindingRoot"
|
"name": "setBindingRoot"
|
||||||
|
@ -1247,9 +1247,6 @@
|
||||||
{
|
{
|
||||||
"name": "setCurrentQueryIndex"
|
"name": "setCurrentQueryIndex"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "setDirectiveDirty"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "setDirty"
|
"name": "setDirty"
|
||||||
},
|
},
|
||||||
|
@ -1292,6 +1289,9 @@
|
||||||
{
|
{
|
||||||
"name": "setSanitizeFlag"
|
"name": "setSanitizeFlag"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "setSelectedIndex"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "setStyle"
|
"name": "setStyle"
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,14 +16,5 @@
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// tslint:disable
|
// tslint:disable
|
||||||
|
|
||||||
window.testBlocklist = {
|
window.testBlocklist = {};
|
||||||
"MatSidenav should be fixed position when in fixed mode": {
|
// clang-format on
|
||||||
"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
|
|
Loading…
Reference in New Issue