From bb52fb798c8578c461d21aee2b7623232184a5d3 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Fri, 6 Dec 2019 14:24:09 -0800 Subject: [PATCH] fix(ivy): handle SafeStyles in [style.prop] correctly (#34286) Prior to this commit, values wrapped into SafeStyle were not handled correctly in [style.prop] bindings in case style sanitizer is present (when template contains some style props that require sanitization). Style sanitizer was not unwrapping values in case a given prop doesn't require sanitization.As a result, wrapped values were used as final styling values (see https://github.com/angular/angular/blob/master/packages/core/src/render3/styling/bindings.ts#L620). This commit updates the logic to unwrap safe values in sanitizer in case no sanitization is required. PR Close #34286 --- .../core/src/sanitization/sanitization.ts | 2 +- packages/core/test/acceptance/styling_spec.ts | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index 9644cf3194..ba64c67a6a 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -196,7 +196,7 @@ export const ɵɵdefaultStyleSanitizer = } if (mode & StyleSanitizeMode.SanitizeOnly) { - return doSanitizeValue ? ɵɵsanitizeStyle(value) : value; + return doSanitizeValue ? ɵɵsanitizeStyle(value) : unwrapSafeValue(value); } else { return doSanitizeValue; } diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts index c3e5874557..b9b3fc3174 100644 --- a/packages/core/test/acceptance/styling_spec.ts +++ b/packages/core/test/acceptance/styling_spec.ts @@ -5,6 +5,7 @@ * 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 {CommonModule} from '@angular/common'; import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostBinding, Input, NgModule, Renderer2, ViewChild, ViewContainerRef} from '@angular/core'; import {getDebugNode} from '@angular/core/src/render3/util/discovery_utils'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; @@ -1563,6 +1564,64 @@ describe('styling', () => { expect(html).toMatch(/style=["|']clip-path:\s*url\(.*#test.*\)/); }); + it('should handle values wrapped into SafeValue', () => { + @Component({ + template: ` + +
+ + +

+ + + + `, + }) + class MyComp { + constructor(private sanitizer: DomSanitizer) {} + public width: string = 'calc(20%)'; + public height: string = '10px'; + public background: string = '1.png'; + public color: string = 'red'; + + private getSafeStyle(value: string) { return this.sanitizer.bypassSecurityTrustStyle(value); } + + getBackgroundSafe() { return this.getSafeStyle(`url("/${this.background}")`); } + getWidthSafe() { return this.getSafeStyle(this.width); } + getHeightSafe() { return this.getSafeStyle(this.height); } + getColorUnsafe() { return this.color; } + } + + TestBed.configureTestingModule({ + imports: [CommonModule], + declarations: [MyComp], + }); + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + const comp = fixture.componentInstance; + const div = fixture.nativeElement.querySelector('div'); + const p = fixture.nativeElement.querySelector('p'); + const span = fixture.nativeElement.querySelector('span'); + + expect(div.style.background).toContain('url("/1.png")'); + expect(p.style.width).toBe('calc(20%)'); + expect(p.style.height).toBe('10px'); + expect(span.style.color).toBe('red'); + + comp.background = '2.png'; + comp.width = '5px'; + comp.height = '100%'; + comp.color = 'green'; + + fixture.detectChanges(); + + expect(div.style.background).toContain('url("/2.png")'); + expect(p.style.width).toBe('5px'); + expect(p.style.height).toBe('100%'); + expect(span.style.color).toBe('green'); + }); + onlyInIvy('only ivy has style/class bindings debugging support') .it('should evaluate follow-up [style] maps even if a former map is null', () => { @Directive({selector: '[dir-with-styling]'})