feat(ivy): properly apply style="", [style], [style.foo] and [attr.style] bindings (#24602)
PR Close #24602
This commit is contained in:

committed by
Miško Hevery

parent
52d43a99ef
commit
3980640d53
@ -11,7 +11,7 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
|
||||
import * as $r3$ from '../../../src/core_render3_private_export';
|
||||
import {AttributeMarker} from '../../../src/render3';
|
||||
import {ComponentDefInternal} from '../../../src/render3/interfaces/definition';
|
||||
import {ComponentDefInternal, InitialStylingFlags} from '../../../src/render3/interfaces/definition';
|
||||
import {ComponentFixture, renderComponent, toHtml} from '../render_util';
|
||||
|
||||
|
||||
@ -304,6 +304,7 @@ describe('elements', () => {
|
||||
it('should bind to a specific style', () => {
|
||||
type $MyComponent$ = MyComponent;
|
||||
|
||||
const c0 = ['color', 'width'];
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: `<div [style.color]="someColor" [style.width.px]="someWidth"></div>`
|
||||
@ -318,11 +319,14 @@ describe('elements', () => {
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵEe(0, 'div');
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵs(1, c0);
|
||||
$r3$.ɵe();
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵsn(0, 'color', $r3$.ɵb(ctx.someColor));
|
||||
$r3$.ɵsn(0, 'width', $r3$.ɵb(ctx.someWidth), 'px');
|
||||
$r3$.ɵsp(1, 0, ctx.someColor);
|
||||
$r3$.ɵsp(1, 1, ctx.someWidth, 'px');
|
||||
$r3$.ɵsa(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -349,10 +353,7 @@ describe('elements', () => {
|
||||
it('should bind to many and keep order', () => {
|
||||
type $MyComponent$ = MyComponent;
|
||||
|
||||
// NORMATIVE
|
||||
const $e0_attrs$ = ['style', 'color: red;'];
|
||||
// /NORMATIVE
|
||||
|
||||
const c0 = ['color', InitialStylingFlags.INITIAL_STYLES, 'color', 'red'];
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template:
|
||||
@ -367,7 +368,9 @@ describe('elements', () => {
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵEe(0, 'div', $e0_attrs$);
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵs(1, c0);
|
||||
$r3$.ɵe();
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵp(0, 'id', $r3$.ɵb(ctx.someString + 1));
|
||||
@ -402,11 +405,14 @@ describe('elements', () => {
|
||||
factory: function StyleComponent_Factory() { return new StyleComponent(); },
|
||||
template: function StyleComponent_Template(rf: $RenderFlags$, ctx: $StyleComponent$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵEe(0, 'div');
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵs(1);
|
||||
$r3$.ɵe();
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵk(0, $r3$.ɵb(ctx.classExp));
|
||||
$r3$.ɵs(0, $r3$.ɵb(ctx.styleExp));
|
||||
$r3$.ɵsm(1, ctx.styleExp);
|
||||
$r3$.ɵsa(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -43,15 +43,18 @@ describe('compiler sanitization', () => {
|
||||
factory: function MyComponent_Factory() { return new MyComponent(); },
|
||||
template: function MyComponent_Template(rf: $RenderFlags$, ctx: $MyComponent$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵEe(0, 'div');
|
||||
$r3$.ɵEe(1, 'img');
|
||||
$r3$.ɵE(0, 'div');
|
||||
$r3$.ɵs(1, ['background-image']);
|
||||
$r3$.ɵe();
|
||||
$r3$.ɵEe(2, 'img');
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵp(0, 'innerHTML', $r3$.ɵb(ctx.innerHTML), $r3$.ɵsanitizeHtml);
|
||||
$r3$.ɵp(0, 'hidden', $r3$.ɵb(ctx.hidden));
|
||||
$r3$.ɵsn(1, 'background-image', $r3$.ɵb(ctx.style), $r3$.ɵsanitizeStyle);
|
||||
$r3$.ɵp(1, 'src', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
|
||||
$r3$.ɵa(1, 'srcset', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
|
||||
$r3$.ɵsp(1, 0, ctx.style, $r3$.ɵsanitizeStyle);
|
||||
$r3$.ɵsa(1);
|
||||
$r3$.ɵp(2, 'src', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
|
||||
$r3$.ɵa(2, 'srcset', $r3$.ɵb(ctx.url), $r3$.ɵsanitizeUrl);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -10,7 +10,8 @@ import {NgForOfContext} from '@angular/common';
|
||||
|
||||
import {RenderFlags, directiveInject} from '../../src/render3';
|
||||
import {defineComponent} from '../../src/render3/definition';
|
||||
import {bind, container, element, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleNamed, interpolation1, renderTemplate, text, textBinding} from '../../src/render3/instructions';
|
||||
import {bind, container, element, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleProp, elementStyling, elementStylingApply, interpolation1, renderTemplate, text, textBinding} from '../../src/render3/instructions';
|
||||
import {InitialStylingFlags} from '../../src/render3/interfaces/definition';
|
||||
import {AttributeMarker, LElementNode, LNode} from '../../src/render3/interfaces/node';
|
||||
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
||||
import {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
|
||||
@ -22,11 +23,13 @@ import {ComponentFixture, TemplateFixture} from './render_util';
|
||||
describe('instructions', () => {
|
||||
function createAnchor() {
|
||||
elementStart(0, 'a');
|
||||
elementStyling(1);
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
function createDiv() {
|
||||
function createDiv(initialStyles?: (string | number)[]) {
|
||||
elementStart(0, 'div');
|
||||
elementStyling(1, initialStyles && Array.isArray(initialStyles) ? initialStyles : null);
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
@ -186,32 +189,38 @@ describe('instructions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('elementStyleNamed', () => {
|
||||
describe('elementStyleProp', () => {
|
||||
it('should use sanitizer function', () => {
|
||||
const t = new TemplateFixture(createDiv);
|
||||
t.update(
|
||||
() => elementStyleNamed(0, 'background-image', 'url("http://server")', sanitizeStyle));
|
||||
const t = new TemplateFixture(() => { return createDiv(['background-image']); });
|
||||
t.update(() => {
|
||||
elementStyleProp(1, 0, 'url("http://server")', sanitizeStyle);
|
||||
elementStylingApply(1);
|
||||
});
|
||||
// nothing is set because sanitizer suppresses it.
|
||||
expect(t.html).toEqual('<div></div>');
|
||||
|
||||
t.update(
|
||||
() => elementStyleNamed(
|
||||
0, 'background-image', bypassSanitizationTrustStyle('url("http://server")'),
|
||||
sanitizeStyle));
|
||||
t.update(() => {
|
||||
elementStyleProp(1, 0, bypassSanitizationTrustStyle('url("http://server")'), sanitizeStyle);
|
||||
elementStylingApply(1);
|
||||
});
|
||||
expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image'))
|
||||
.toEqual('url("http://server")');
|
||||
});
|
||||
});
|
||||
|
||||
describe('elementStyle', () => {
|
||||
describe('elementStyleMap', () => {
|
||||
function createDivWithStyle() {
|
||||
elementStart(0, 'div', ['style', 'height: 10px']);
|
||||
elementStart(0, 'div');
|
||||
elementStyling(1, ['height', InitialStylingFlags.INITIAL_STYLES, 'height', '10px']);
|
||||
elementEnd();
|
||||
}
|
||||
|
||||
it('should add style', () => {
|
||||
const fixture = new TemplateFixture(createDivWithStyle);
|
||||
fixture.update(() => elementStyle(0, {'background-color': 'red'}));
|
||||
fixture.update(() => {
|
||||
elementStyle(1, {'background-color': 'red'});
|
||||
elementStylingApply(1);
|
||||
});
|
||||
expect(fixture.html).toEqual('<div style="height: 10px; background-color: red;"></div>');
|
||||
});
|
||||
});
|
||||
|
@ -9,7 +9,7 @@
|
||||
import {RenderFlags} from '@angular/core/src/render3';
|
||||
|
||||
import {defineComponent, defineDirective} from '../../src/render3/index';
|
||||
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleNamed, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, loadDirective, projection, projectionDef, text, textBinding,} from '../../src/render3/instructions';
|
||||
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, elementAttribute, elementClassNamed, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
|
||||
import {HEADER_OFFSET} from '../../src/render3/interfaces/view';
|
||||
import {sanitizeUrl} from '../../src/sanitization/sanitization';
|
||||
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
|
||||
@ -747,10 +747,12 @@ describe('render3 integration test', () => {
|
||||
function Template(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'span');
|
||||
elementStyling(1, ['border-color']);
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementStyleNamed(0, 'border-color', bind(ctx));
|
||||
elementStyleProp(1, 0, ctx);
|
||||
elementStylingApply(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -764,10 +766,12 @@ describe('render3 integration test', () => {
|
||||
function Template(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'span');
|
||||
elementStyling(1, ['font-size']);
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementStyleNamed(0, 'font-size', bind(ctx), 'px');
|
||||
elementStyleProp(1, 0, ctx, 'px');
|
||||
elementStylingApply(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,8 @@ function testLStaticData(tagName: string, attrs: TAttributes | null): TNode {
|
||||
child: null,
|
||||
parent: null,
|
||||
dynamicContainerNode: null,
|
||||
detached: null
|
||||
detached: null,
|
||||
stylingTemplate: null
|
||||
};
|
||||
}
|
||||
|
||||
|
657
packages/core/test/render3/styling_spec.ts
Normal file
657
packages/core/test/render3/styling_spec.ts
Normal file
@ -0,0 +1,657 @@
|
||||
/**
|
||||
* @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 {elementEnd, elementStart, elementStyle, elementStyleProp, elementStyling, elementStylingApply} from '../../src/render3/instructions';
|
||||
import {InitialStylingFlags, RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
import {LElementNode} from '../../src/render3/interfaces/node';
|
||||
import {Renderer3} from '../../src/render3/interfaces/renderer';
|
||||
import {StylingContext, StylingFlags, StylingIndex, allocStylingContext, createStylingContextTemplate, isContextDirty, renderStyles as _renderStyles, setContextDirty, updateStyleMap, updateStyleProp} from '../../src/render3/styling';
|
||||
|
||||
import {renderToHtml} from './render_util';
|
||||
|
||||
describe('styling', () => {
|
||||
let lElement: LElementNode|null = null;
|
||||
beforeEach(() => { lElement = { native: {} } as any; });
|
||||
|
||||
function initContext(styles?: (number | string)[]): StylingContext {
|
||||
return allocStylingContext(createStylingContextTemplate(styles));
|
||||
}
|
||||
|
||||
function renderStyles(context: StylingContext, renderer?: Renderer3) {
|
||||
const styles: {[key: string]: any} = {};
|
||||
_renderStyles(lElement !, context, (renderer || {}) as Renderer3, styles);
|
||||
return styles;
|
||||
}
|
||||
|
||||
function trackStylesFactory() {
|
||||
const styles: {[key: string]: any} = {};
|
||||
return function(context: StylingContext, renderer?: Renderer3): {[key: string]: any} {
|
||||
_renderStyles(lElement !, context, (renderer || {}) as Renderer3, styles);
|
||||
return styles;
|
||||
};
|
||||
}
|
||||
|
||||
function clean(a: number = 0, b: number = 0): number {
|
||||
let num = 0;
|
||||
if (a) {
|
||||
num |= a << StylingFlags.BitCountSize;
|
||||
}
|
||||
if (b) {
|
||||
num |= b << (StylingFlags.BitCountSize + StylingIndex.BitCountSize);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
function dirty(a: number = 0, b: number = 0): number { return clean(a, b) | StylingFlags.Dirty; }
|
||||
|
||||
describe('createStylingContextTemplate', () => {
|
||||
it('should initialize empty template', () => {
|
||||
const template = createStylingContextTemplate();
|
||||
expect(template).toEqual([
|
||||
[null],
|
||||
clean(0, 2),
|
||||
]);
|
||||
});
|
||||
|
||||
it('should initialize static styles', () => {
|
||||
debugger;
|
||||
const template = createStylingContextTemplate(
|
||||
[InitialStylingFlags.INITIAL_STYLES, 'color', 'red', 'width', '10px']);
|
||||
expect(template).toEqual([
|
||||
[null, 'red', '10px'],
|
||||
dirty(0, 8), //
|
||||
|
||||
// #2
|
||||
clean(1, 8),
|
||||
'color',
|
||||
null,
|
||||
|
||||
// #5
|
||||
clean(2, 11),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #8
|
||||
dirty(1, 2),
|
||||
'color',
|
||||
null,
|
||||
|
||||
// #11
|
||||
dirty(2, 5),
|
||||
'width',
|
||||
null,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('instructions', () => {
|
||||
it('should handle a combination of initial, multi and singular style values (in that order)',
|
||||
() => {
|
||||
function Template(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'span');
|
||||
elementStyling(1, [
|
||||
'width', 'height', 'opacity', //
|
||||
0, 'width', '100px', 'height', '100px', 'opacity', '0.5'
|
||||
]);
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
elementStyle(1, ctx.myStyles);
|
||||
elementStyleProp(1, 0, ctx.myWidth);
|
||||
elementStylingApply(1);
|
||||
}
|
||||
}
|
||||
|
||||
expect(renderToHtml(Template, {
|
||||
myStyles: {width: '200px', height: '200px'},
|
||||
myWidth: '300px'
|
||||
})).toEqual('<span style="width: 300px; height: 200px; opacity: 0.5;"></span>');
|
||||
|
||||
expect(renderToHtml(Template, {myStyles: {width: '200px', height: null}, myWidth: null}))
|
||||
.toEqual('<span style="width: 200px; height: 100px; opacity: 0.5;"></span>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('helper functions', () => {
|
||||
it('should build a list of multiple styling values', () => {
|
||||
const getStyles = trackStylesFactory();
|
||||
const stylingContext = initContext();
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
updateStyleMap(stylingContext, {height: '200px'});
|
||||
expect(getStyles(stylingContext)).toEqual({width: null, height: '200px'});
|
||||
});
|
||||
|
||||
it('should evaluate the delta between style changes when rendering occurs', () => {
|
||||
const stylingContext = initContext(['width', 'height', 0, 'width', '100px']);
|
||||
updateStyleMap(stylingContext, {
|
||||
height: '200px',
|
||||
});
|
||||
expect(renderStyles(stylingContext)).toEqual({width: '100px', height: '200px'});
|
||||
expect(renderStyles(stylingContext)).toEqual({});
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
expect(renderStyles(stylingContext)).toEqual({height: '100px'});
|
||||
updateStyleProp(stylingContext, 1, '100px');
|
||||
expect(renderStyles(stylingContext)).toEqual({});
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
expect(renderStyles(stylingContext)).toEqual({});
|
||||
});
|
||||
|
||||
it('should update individual values on a set of styles', () => {
|
||||
const getStyles = trackStylesFactory();
|
||||
const stylingContext = initContext(['width', 'height']);
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
updateStyleProp(stylingContext, 1, '200px');
|
||||
expect(getStyles(stylingContext)).toEqual({width: '100px', height: '200px'});
|
||||
});
|
||||
|
||||
it('should only mark itself as updated when one or more properties have been applied', () => {
|
||||
const stylingContext = initContext();
|
||||
expect(isContextDirty(stylingContext)).toBeFalsy();
|
||||
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
expect(isContextDirty(stylingContext)).toBeTruthy();
|
||||
|
||||
setContextDirty(stylingContext, false);
|
||||
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
expect(isContextDirty(stylingContext)).toBeFalsy();
|
||||
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '200px',
|
||||
height: '100px',
|
||||
});
|
||||
expect(isContextDirty(stylingContext)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should only mark itself as updated when any single properties have been applied', () => {
|
||||
const stylingContext = initContext(['height']);
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
});
|
||||
|
||||
setContextDirty(stylingContext, false);
|
||||
|
||||
updateStyleProp(stylingContext, 0, '100px');
|
||||
expect(isContextDirty(stylingContext)).toBeFalsy();
|
||||
|
||||
setContextDirty(stylingContext, false);
|
||||
|
||||
updateStyleProp(stylingContext, 0, '200px');
|
||||
expect(isContextDirty(stylingContext)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should prioritize multi and single styles over initial styles', () => {
|
||||
const getStyles = trackStylesFactory();
|
||||
|
||||
const stylingContext = initContext(
|
||||
['width', 'height', 'opacity', 0, 'width', '100px', 'height', '100px', 'opacity', '0']);
|
||||
|
||||
expect(getStyles(stylingContext)).toEqual({
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
opacity: '0',
|
||||
});
|
||||
|
||||
updateStyleMap(stylingContext, {width: '200px', height: '200px'});
|
||||
|
||||
expect(getStyles(stylingContext)).toEqual({
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
opacity: '0',
|
||||
});
|
||||
|
||||
updateStyleProp(stylingContext, 0, '300px');
|
||||
|
||||
expect(getStyles(stylingContext)).toEqual({
|
||||
width: '300px',
|
||||
height: '200px',
|
||||
opacity: '0',
|
||||
});
|
||||
|
||||
updateStyleProp(stylingContext, 0, null);
|
||||
|
||||
expect(getStyles(stylingContext)).toEqual({
|
||||
width: '200px',
|
||||
height: '200px',
|
||||
opacity: '0',
|
||||
});
|
||||
|
||||
updateStyleMap(stylingContext, {});
|
||||
|
||||
expect(getStyles(stylingContext)).toEqual({
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
opacity: '0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should cleanup removed styles from the context once the styles are built', () => {
|
||||
const stylingContext = initContext(['width', 'height']);
|
||||
const getStyles = trackStylesFactory();
|
||||
|
||||
updateStyleMap(stylingContext, {width: '100px', height: '100px'});
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 8), //
|
||||
|
||||
// #2
|
||||
clean(0, 8),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #5
|
||||
clean(0, 11),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #8
|
||||
dirty(0, 2),
|
||||
'width',
|
||||
'100px',
|
||||
|
||||
// #11
|
||||
dirty(0, 5),
|
||||
'height',
|
||||
'100px',
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
updateStyleMap(stylingContext, {width: '200px', opacity: '0'});
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 8), //
|
||||
|
||||
// #2
|
||||
clean(0, 8),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #5
|
||||
clean(0, 14),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #8
|
||||
dirty(0, 2),
|
||||
'width',
|
||||
'200px',
|
||||
|
||||
// #11
|
||||
dirty(),
|
||||
'opacity',
|
||||
'0',
|
||||
|
||||
// #14
|
||||
dirty(0, 5),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
clean(0, 8), //
|
||||
|
||||
// #2
|
||||
clean(0, 8),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #5
|
||||
clean(0, 14),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #8
|
||||
clean(0, 2),
|
||||
'width',
|
||||
'200px',
|
||||
|
||||
// #11
|
||||
clean(),
|
||||
'opacity',
|
||||
'0',
|
||||
|
||||
// #14
|
||||
clean(0, 5),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
|
||||
updateStyleMap(stylingContext, {width: null});
|
||||
updateStyleProp(stylingContext, 0, '300px');
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 8), //
|
||||
|
||||
// #2
|
||||
dirty(0, 8),
|
||||
'width',
|
||||
'300px',
|
||||
|
||||
// #5
|
||||
clean(0, 14),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #8
|
||||
clean(0, 2),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #11
|
||||
dirty(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(0, 5),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
|
||||
updateStyleProp(stylingContext, 0, null);
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 8), //
|
||||
|
||||
// #2
|
||||
dirty(0, 8),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #5
|
||||
clean(0, 14),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #8
|
||||
clean(0, 2),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #11
|
||||
clean(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(0, 5),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should find the next available space in the context when data is added after being removed before',
|
||||
() => {
|
||||
const stylingContext = initContext(['lineHeight']);
|
||||
const getStyles = trackStylesFactory();
|
||||
|
||||
updateStyleMap(stylingContext, {width: '100px', height: '100px', opacity: '0.5'});
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
clean(0, 14),
|
||||
'lineHeight',
|
||||
null,
|
||||
|
||||
// #5
|
||||
dirty(),
|
||||
'width',
|
||||
'100px',
|
||||
|
||||
// #8
|
||||
dirty(),
|
||||
'height',
|
||||
'100px',
|
||||
|
||||
// #11
|
||||
dirty(),
|
||||
'opacity',
|
||||
'0.5',
|
||||
|
||||
// #14
|
||||
dirty(0, 2),
|
||||
'lineHeight',
|
||||
null,
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
|
||||
updateStyleMap(stylingContext, {});
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
clean(0, 14),
|
||||
'lineHeight',
|
||||
null,
|
||||
|
||||
// #5
|
||||
dirty(),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #8
|
||||
dirty(),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #11
|
||||
dirty(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(0, 2),
|
||||
'lineHeight',
|
||||
null,
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
updateStyleMap(stylingContext, {
|
||||
borderWidth: '5px',
|
||||
});
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
clean(0, 17),
|
||||
'lineHeight',
|
||||
null,
|
||||
|
||||
// #5
|
||||
dirty(),
|
||||
'borderWidth',
|
||||
'5px',
|
||||
|
||||
// #8
|
||||
clean(),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #11
|
||||
clean(),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #17
|
||||
clean(0, 2),
|
||||
'lineHeight',
|
||||
null,
|
||||
]);
|
||||
|
||||
updateStyleProp(stylingContext, 0, '200px');
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
dirty(0, 17),
|
||||
'lineHeight',
|
||||
'200px',
|
||||
|
||||
// #5
|
||||
dirty(),
|
||||
'borderWidth',
|
||||
'5px',
|
||||
|
||||
// #8
|
||||
clean(),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #11
|
||||
clean(),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #17
|
||||
clean(0, 2),
|
||||
'lineHeight',
|
||||
null,
|
||||
]);
|
||||
|
||||
updateStyleMap(stylingContext, {borderWidth: '15px', borderColor: 'red'});
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
dirty(0, 20),
|
||||
'lineHeight',
|
||||
'200px',
|
||||
|
||||
// #5
|
||||
dirty(),
|
||||
'borderWidth',
|
||||
'15px',
|
||||
|
||||
// #8
|
||||
dirty(),
|
||||
'borderColor',
|
||||
'red',
|
||||
|
||||
// #11
|
||||
clean(),
|
||||
'width',
|
||||
null,
|
||||
|
||||
// #14
|
||||
clean(),
|
||||
'height',
|
||||
null,
|
||||
|
||||
// #17
|
||||
clean(),
|
||||
'opacity',
|
||||
null,
|
||||
|
||||
// #20
|
||||
clean(0, 2),
|
||||
'lineHeight',
|
||||
null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should render all data as not being dirty after the styles are built', () => {
|
||||
const getStyles = trackStylesFactory();
|
||||
const stylingContext = initContext(['height']);
|
||||
|
||||
updateStyleMap(stylingContext, {
|
||||
width: '100px',
|
||||
});
|
||||
|
||||
updateStyleProp(stylingContext, 0, '200px');
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
dirty(0, 5), //
|
||||
|
||||
// #2
|
||||
dirty(0, 8),
|
||||
'height',
|
||||
'200px',
|
||||
|
||||
// #2
|
||||
dirty(),
|
||||
'width',
|
||||
'100px',
|
||||
|
||||
// #8
|
||||
clean(0, 2),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
|
||||
getStyles(stylingContext);
|
||||
|
||||
expect(stylingContext).toEqual([
|
||||
[null],
|
||||
clean(0, 5), //
|
||||
|
||||
// #2
|
||||
clean(0, 8),
|
||||
'height',
|
||||
'200px',
|
||||
|
||||
// #2
|
||||
clean(),
|
||||
'width',
|
||||
'100px',
|
||||
|
||||
// #8
|
||||
clean(0, 2),
|
||||
'height',
|
||||
null,
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user