Miško Hevery 5aabe93abe refactor(ivy): Switch styling to new reconcile algorithm (#34616)
NOTE: This change must be reverted with previous deletes so that it code remains in build-able state.

This change deletes old styling code and replaces it with a simplified styling algorithm.

The mental model for the new algorithm is:
- Create a linked list of styling bindings in the order of priority. All styling bindings ere executed in compiled order and than a linked list of bindings is created in priority order.
- Flush the style bindings at the end of `advance()` instruction. This implies that there are two flush events. One at the end of template `advance` instruction in the template. Second one at the end of `hostBindings` `advance` instruction when processing host bindings (if any).
- Each binding instructions effectively updates the string to represent the string at that location. Because most of the bindings are additive, this is a cheap strategy in most cases. In rare cases the strategy requires removing tokens from the styling up to this point. (We expect that to be rare case)S Because, the bindings are presorted in the order of priority, it is safe to resume the processing of the concatenated string from the last change binding.

PR Close #34616
2020-01-24 12:23:00 -08:00

84 lines
2.5 KiB
TypeScript

/**
* @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
*/
/**
* Returns element classes in form of a stable (sorted) string.
*
* @param element HTML Element.
* @returns Returns element classes in form of a stable (sorted) string.
*/
export function getSortedClassName(element: Element): string {
const names: string[] = Object.keys(getElementClasses(element));
names.sort();
return names.join(' ');
}
/**
* Returns element classes in form of a map.
*
* @param element HTML Element.
* @returns Map of class values.
*/
export function getElementClasses(element: Element): {[key: string]: true} {
const classes: {[key: string]: true} = {};
if (element.nodeType === Node.ELEMENT_NODE) {
const classList = element.classList;
for (let i = 0; i < classList.length; i++) {
const key = classList[i];
classes[key] = true;
}
}
return classes;
}
/**
* Returns element styles in form of a stable (sorted) string.
*
* @param element HTML Element.
* @returns Returns element styles in form of a stable (sorted) string.
*/
export function getSortedStyle(element: Element): string {
const styles = getElementStyles(element);
const names: string[] = Object.keys(styles);
names.sort();
let sorted = '';
names.forEach(key => {
const value = styles[key];
if (value != null && value !== '') {
if (sorted !== '') sorted += ' ';
sorted += key + ': ' + value + ';';
}
});
return sorted;
}
/**
* Returns element styles in form of a map.
*
* @param element HTML Element.
* @returns Map of style values.
*/
export function getElementStyles(element: Element): {[key: string]: string} {
const styles: {[key: string]: string} = {};
if (element.nodeType === Node.ELEMENT_NODE) {
const style = (element as HTMLElement).style;
// reading `style.color` is a work around for a bug in Domino. The issue is that Domino has
// stale value for `style.length`. It seems that reading a property from the element causes the
// stale value to be updated. (As of Domino v 2.1.3)
style.color;
for (let i = 0; i < style.length; i++) {
const key = style.item(i);
const value = style.getPropertyValue(key);
if (value !== '') {
// Workaround for IE not clearing properties, instead it just sets them to blank value.
styles[key] = value;
}
}
}
return styles;
}