2019-05-08 16:30:28 -07:00
|
|
|
/**
|
|
|
|
|
* @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
|
|
|
|
|
*/
|
2019-09-09 13:14:26 -07:00
|
|
|
import {RElement} from '../interfaces/renderer';
|
2019-09-27 11:57:50 -07:00
|
|
|
import {StylingMapArray} from '../interfaces/styling';
|
2019-09-17 14:59:20 -07:00
|
|
|
import {TEMPLATE_DIRECTIVE_INDEX} from '../util/styling_utils';
|
2019-05-24 13:49:57 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* --------
|
|
|
|
|
*
|
2019-05-28 10:31:01 -07:00
|
|
|
* This file contains all state-based logic for styling in Angular.
|
|
|
|
|
*
|
|
|
|
|
* Styling in Angular is evaluated with a series of styling-specific
|
|
|
|
|
* template instructions which are called one after another each time
|
|
|
|
|
* change detection occurs in Angular.
|
|
|
|
|
*
|
|
|
|
|
* Styling makes use of various temporary, state-based variables between
|
|
|
|
|
* instructions so that it can better cache and optimize its values.
|
|
|
|
|
* These values are usually populated and cleared when an element is
|
|
|
|
|
* exited in change detection (once all the instructions are run for
|
|
|
|
|
* that element).
|
|
|
|
|
*
|
|
|
|
|
* To learn more about the algorithm see `TStylingContext`.
|
2019-05-24 13:49:57 -07:00
|
|
|
*
|
|
|
|
|
* --------
|
|
|
|
|
*/
|
2019-05-08 16:30:28 -07:00
|
|
|
|
|
|
|
|
/**
|
2019-05-28 10:31:01 -07:00
|
|
|
* Used as a state reference for update values between style/class binding instructions.
|
2019-09-09 13:14:26 -07:00
|
|
|
*
|
|
|
|
|
* In addition to storing the element and bit-mask related values, the state also
|
|
|
|
|
* stores the `sourceIndex` value. The `sourceIndex` value is an incremented value
|
|
|
|
|
* that identifies what "source" (i.e. the template, a specific directive by index or
|
|
|
|
|
* component) is currently applying its styling bindings to the element.
|
2019-05-08 16:30:28 -07:00
|
|
|
*/
|
2019-05-28 10:31:01 -07:00
|
|
|
export interface StylingState {
|
2019-09-09 13:14:26 -07:00
|
|
|
/** The element that is currently being processed */
|
|
|
|
|
element: RElement|null;
|
|
|
|
|
|
|
|
|
|
/** The directive index that is currently active (`0` === template) */
|
|
|
|
|
directiveIndex: number;
|
|
|
|
|
|
|
|
|
|
/** The source (column) index that is currently active (`0` === template) */
|
|
|
|
|
sourceIndex: number;
|
|
|
|
|
|
|
|
|
|
/** The classes update bit mask value that is processed during each class binding */
|
2019-05-28 10:31:01 -07:00
|
|
|
classesBitMask: number;
|
2019-09-09 13:14:26 -07:00
|
|
|
|
|
|
|
|
/** The classes update bit index value that is processed during each class binding */
|
2019-05-28 10:31:01 -07:00
|
|
|
classesIndex: number;
|
2019-09-09 13:14:26 -07:00
|
|
|
|
|
|
|
|
/** The styles update bit mask value that is processed during each style binding */
|
2019-05-28 10:31:01 -07:00
|
|
|
stylesBitMask: number;
|
2019-09-09 13:14:26 -07:00
|
|
|
|
|
|
|
|
/** The styles update bit index value that is processed during each style binding */
|
2019-05-28 10:31:01 -07:00
|
|
|
stylesIndex: number;
|
2019-09-27 11:57:50 -07:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The last class map that was applied (i.e. `[class]="x"`).
|
|
|
|
|
*
|
|
|
|
|
* Note that this property is only populated when direct class values are applied
|
|
|
|
|
* (i.e. context resolution is not used).
|
|
|
|
|
*
|
|
|
|
|
* See `allowDirectStyling` for more info.
|
|
|
|
|
*/
|
|
|
|
|
lastDirectClassMap: StylingMapArray|null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The last style map that was applied (i.e. `[style]="x"`)
|
|
|
|
|
*
|
|
|
|
|
* Note that this property is only populated when direct style values are applied
|
|
|
|
|
* (i.e. context resolution is not used).
|
|
|
|
|
*
|
|
|
|
|
* See `allowDirectStyling` for more info.
|
|
|
|
|
*/
|
|
|
|
|
lastDirectStyleMap: StylingMapArray|null;
|
2019-05-08 16:30:28 -07:00
|
|
|
}
|
|
|
|
|
|
2019-09-09 13:14:26 -07:00
|
|
|
// these values will get filled in the very first time this is accessed...
|
|
|
|
|
const _state: StylingState = {
|
|
|
|
|
element: null,
|
|
|
|
|
directiveIndex: -1,
|
|
|
|
|
sourceIndex: -1,
|
|
|
|
|
classesBitMask: -1,
|
|
|
|
|
classesIndex: -1,
|
|
|
|
|
stylesBitMask: -1,
|
|
|
|
|
stylesIndex: -1,
|
2019-09-27 11:57:50 -07:00
|
|
|
lastDirectClassMap: null,
|
|
|
|
|
lastDirectStyleMap: null,
|
2019-09-09 13:14:26 -07:00
|
|
|
};
|
2019-09-10 18:08:05 -04:00
|
|
|
|
2019-09-09 13:14:26 -07:00
|
|
|
const BIT_MASK_START_VALUE = 0;
|
2019-09-11 15:24:10 -07:00
|
|
|
|
2019-09-09 13:14:26 -07:00
|
|
|
// the `0` start value is reserved for [map]-based entries
|
|
|
|
|
const INDEX_START_VALUE = 1;
|
2019-09-11 15:24:10 -07:00
|
|
|
|
2019-09-09 13:14:26 -07:00
|
|
|
/**
|
|
|
|
|
* Returns (or instantiates) the styling state for the given element.
|
|
|
|
|
*
|
|
|
|
|
* Styling state is accessed and processed each time a style or class binding
|
|
|
|
|
* is evaluated.
|
|
|
|
|
*
|
|
|
|
|
* If and when the provided `element` doesn't match the current element in the
|
|
|
|
|
* state then this means that styling was recently cleared or the element has
|
|
|
|
|
* changed in change detection. In both cases the styling state is fully reset.
|
|
|
|
|
*
|
|
|
|
|
* If and when the provided `directiveIndex` doesn't match the current directive
|
|
|
|
|
* index in the state then this means that a new source has introduced itself into
|
|
|
|
|
* the styling code (or, in other words, another directive or component has started
|
|
|
|
|
* to apply its styling host bindings to the element).
|
|
|
|
|
*/
|
|
|
|
|
export function getStylingState(element: RElement, directiveIndex: number): StylingState {
|
|
|
|
|
if (_state.element !== element) {
|
|
|
|
|
_state.element = element;
|
|
|
|
|
_state.directiveIndex = directiveIndex;
|
|
|
|
|
_state.sourceIndex = directiveIndex === TEMPLATE_DIRECTIVE_INDEX ? 0 : 1;
|
|
|
|
|
_state.classesBitMask = BIT_MASK_START_VALUE;
|
|
|
|
|
_state.classesIndex = INDEX_START_VALUE;
|
|
|
|
|
_state.stylesBitMask = BIT_MASK_START_VALUE;
|
|
|
|
|
_state.stylesIndex = INDEX_START_VALUE;
|
2019-09-27 11:57:50 -07:00
|
|
|
_state.lastDirectClassMap = null;
|
|
|
|
|
_state.lastDirectStyleMap = null;
|
2019-09-09 13:14:26 -07:00
|
|
|
} else if (_state.directiveIndex !== directiveIndex) {
|
|
|
|
|
_state.directiveIndex = directiveIndex;
|
|
|
|
|
_state.sourceIndex++;
|
|
|
|
|
}
|
|
|
|
|
return _state;
|
2019-09-11 15:24:10 -07:00
|
|
|
}
|
|
|
|
|
|
2019-09-09 13:14:26 -07:00
|
|
|
/**
|
|
|
|
|
* Clears the styling state so that it can be used by another element's styling code.
|
|
|
|
|
*/
|
|
|
|
|
export function resetStylingState() {
|
|
|
|
|
_state.element = null;
|
2019-05-24 13:49:57 -07:00
|
|
|
}
|