@@ -24,13 +24,15 @@ import {PlayerFactory} from './interfaces/player';
24
24
import { CssSelectorList , NG_PROJECT_AS_ATTR_NAME } from './interfaces/projection' ;
25
25
import { LQueries } from './interfaces/query' ;
26
26
import { ProceduralRenderer3 , RComment , RElement , RNode , RText , Renderer3 , RendererFactory3 , isProceduralRenderer } from './interfaces/renderer' ;
27
+ import { StylingIndex } from './interfaces/styling' ;
27
28
import { BINDING_INDEX , CLEANUP , CONTAINER_INDEX , CONTENT_QUERIES , CONTEXT , CurrentMatchesList , DECLARATION_VIEW , FLAGS , HEADER_OFFSET , HOST , HOST_NODE , INJECTOR , LViewData , LViewFlags , NEXT , OpaqueViewState , PARENT , QUERIES , RENDERER , RootContext , RootContextFlags , SANITIZER , TAIL , TVIEW , TView } from './interfaces/view' ;
28
29
import { assertNodeOfPossibleTypes , assertNodeType } from './node_assert' ;
29
30
import { appendChild , appendProjectedNode , createTextNode , findComponentView , getLViewChild , getRenderParent , insertView , removeView } from './node_manipulation' ;
30
31
import { isNodeMatchingSelectorList , matchingSelectorIndex } from './node_selector_matcher' ;
31
32
import { createStylingContextTemplate , renderStyleAndClassBindings , updateClassProp as updateElementClassProp , updateStyleProp as updateElementStyleProp , updateStylingMap } from './styling/class_and_style_bindings' ;
32
33
import { BoundPlayerFactory } from './styling/player_factory' ;
33
34
import { getStylingContext } from './styling/util' ;
35
+ import { NO_CHANGE } from './tokens' ;
34
36
import { assertDataInRangeInternal , getComponentViewByIndex , getNativeByIndex , getNativeByTNode , getRootContext , getRootView , getTNode , isComponent , isContentQueryHost , isDifferent , loadInternal , readPatchedLViewData , stringify } from './util' ;
35
37
36
38
@@ -1337,14 +1339,7 @@ export function elementProperty<T>(
1337
1339
if ( value === NO_CHANGE ) return ;
1338
1340
const element = getNativeByIndex ( index , viewData ) as RElement | RComment ;
1339
1341
const tNode = getTNode ( index , viewData ) ;
1340
- // if tNode.inputs is undefined, a listener has created outputs, but inputs haven't
1341
- // yet been checked
1342
- if ( tNode && tNode . inputs === undefined ) {
1343
- // mark inputs as checked
1344
- tNode . inputs = generatePropertyAliases ( tNode . flags , BindingDirection . Input ) ;
1345
- }
1346
-
1347
- const inputData = tNode && tNode . inputs ;
1342
+ const inputData = initializeTNodeInputs ( tNode ) ;
1348
1343
let dataValue : PropertyAliasValue | undefined ;
1349
1344
if ( inputData && ( dataValue = inputData [ propName ] ) ) {
1350
1345
setInputsForProperty ( dataValue , value ) ;
@@ -1543,14 +1538,28 @@ export function elementStyling(
1543
1538
styleDeclarations ?: ( string | boolean | InitialStylingFlags ) [ ] | null ,
1544
1539
styleSanitizer ?: StyleSanitizeFn | null ) : void {
1545
1540
const tNode = previousOrParentTNode ;
1541
+ const inputData = initializeTNodeInputs ( tNode ) ;
1542
+
1546
1543
if ( ! tNode . stylingTemplate ) {
1544
+ const hasClassInput = inputData && inputData . hasOwnProperty ( 'class' ) ? true : false ;
1545
+ if ( hasClassInput ) {
1546
+ tNode . flags |= TNodeFlags . hasClassInput ;
1547
+ }
1548
+
1547
1549
// initialize the styling template.
1548
- tNode . stylingTemplate =
1549
- createStylingContextTemplate ( classDeclarations , styleDeclarations , styleSanitizer ) ;
1550
+ tNode . stylingTemplate = createStylingContextTemplate (
1551
+ classDeclarations , styleDeclarations , styleSanitizer , hasClassInput ) ;
1550
1552
}
1553
+
1551
1554
if ( styleDeclarations && styleDeclarations . length ||
1552
1555
classDeclarations && classDeclarations . length ) {
1553
- elementStylingApply ( tNode . index - HEADER_OFFSET ) ;
1556
+ const index = tNode . index - HEADER_OFFSET ;
1557
+ if ( delegateToClassInput ( tNode ) ) {
1558
+ const stylingContext = getStylingContext ( index , viewData ) ;
1559
+ const initialClasses = stylingContext [ StylingIndex . PreviousOrCachedMultiClassValue ] as string ;
1560
+ setInputsForProperty ( tNode . inputs ! [ 'class' ] ! , initialClasses ) ;
1561
+ }
1562
+ elementStylingApply ( index ) ;
1554
1563
}
1555
1564
}
1556
1565
@@ -1640,9 +1649,17 @@ export function elementStyleProp(
1640
1649
* removed (unset) from the element's styling.
1641
1650
*/
1642
1651
export function elementStylingMap < T > (
1643
- index : number , classes : { [ key : string ] : any } | string | null ,
1644
- styles ?: { [ styleName : string ] : any } | null ) : void {
1645
- updateStylingMap ( getStylingContext ( index , viewData ) , classes , styles ) ;
1652
+ index : number , classes : { [ key : string ] : any } | string | NO_CHANGE | null ,
1653
+ styles ?: { [ styleName : string ] : any } | NO_CHANGE | null ) : void {
1654
+ const tNode = getTNode ( index , viewData ) ;
1655
+ const stylingContext = getStylingContext ( index , viewData ) ;
1656
+ if ( delegateToClassInput ( tNode ) && classes !== NO_CHANGE ) {
1657
+ const initialClasses = stylingContext [ StylingIndex . PreviousOrCachedMultiClassValue ] as string ;
1658
+ const classInputVal =
1659
+ ( initialClasses . length ? ( initialClasses + ' ' ) : '' ) + ( classes as string ) ;
1660
+ setInputsForProperty ( tNode . inputs ! [ 'class' ] ! , classInputVal ) ;
1661
+ }
1662
+ updateStylingMap ( stylingContext , classes , styles ) ;
1646
1663
}
1647
1664
1648
1665
//////////////////////////
@@ -2577,14 +2594,6 @@ export function markDirty<T>(component: T) {
2577
2594
//// Bindings & interpolations
2578
2595
///////////////////////////////
2579
2596
2580
- export interface NO_CHANGE {
2581
- // This is a brand that ensures that this type can never match anything else
2582
- brand : 'NO_CHANGE' ;
2583
- }
2584
-
2585
- /** A special value which designates that a value has not changed. */
2586
- export const NO_CHANGE = { } as NO_CHANGE ;
2587
-
2588
2597
/**
2589
2598
* Creates a single value binding.
2590
2599
*
@@ -2871,3 +2880,20 @@ function assertDataNext(index: number, arr?: any[]) {
2871
2880
}
2872
2881
2873
2882
export const CLEAN_PROMISE = _CLEAN_PROMISE ;
2883
+
2884
+ function initializeTNodeInputs ( tNode : TNode | null ) {
2885
+ // If tNode.inputs is undefined, a listener has created outputs, but inputs haven't
2886
+ // yet been checked.
2887
+ if ( tNode ) {
2888
+ if ( tNode . inputs === undefined ) {
2889
+ // mark inputs as checked
2890
+ tNode . inputs = generatePropertyAliases ( tNode . flags , BindingDirection . Input ) ;
2891
+ }
2892
+ return tNode . inputs ;
2893
+ }
2894
+ return null ;
2895
+ }
2896
+
2897
+ export function delegateToClassInput ( tNode : TNode ) {
2898
+ return tNode . flags & TNodeFlags . hasClassInput ;
2899
+ }
0 commit comments