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
This commit is contained in:
parent
2ecf9f3f2a
commit
bb52fb798c
|
@ -196,7 +196,7 @@ export const ɵɵdefaultStyleSanitizer =
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode & StyleSanitizeMode.SanitizeOnly) {
|
if (mode & StyleSanitizeMode.SanitizeOnly) {
|
||||||
return doSanitizeValue ? ɵɵsanitizeStyle(value) : value;
|
return doSanitizeValue ? ɵɵsanitizeStyle(value) : unwrapSafeValue(value);
|
||||||
} else {
|
} else {
|
||||||
return doSanitizeValue;
|
return doSanitizeValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* 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 {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 {getDebugNode} from '@angular/core/src/render3/util/discovery_utils';
|
||||||
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
|
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.*\)/);
|
expect(html).toMatch(/style=["|']clip-path:\s*url\(.*#test.*\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle values wrapped into SafeValue', () => {
|
||||||
|
@Component({
|
||||||
|
template: `
|
||||||
|
<!-- Verify sanitizable style prop values wrapped in SafeValue -->
|
||||||
|
<div [style.background]="getBackgroundSafe()"></div>
|
||||||
|
|
||||||
|
<!-- Verify regular style prop values wrapped in SafeValue -->
|
||||||
|
<p [style.width]="getWidthSafe()" [style.height]="getHeightSafe()"></p>
|
||||||
|
|
||||||
|
<!-- Verify regular style prop values not wrapped in SafeValue -->
|
||||||
|
<span [style.color]="getColorUnsafe()"></span>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
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')
|
onlyInIvy('only ivy has style/class bindings debugging support')
|
||||||
.it('should evaluate follow-up [style] maps even if a former map is null', () => {
|
.it('should evaluate follow-up [style] maps even if a former map is null', () => {
|
||||||
@Directive({selector: '[dir-with-styling]'})
|
@Directive({selector: '[dir-with-styling]'})
|
||||||
|
|
Loading…
Reference in New Issue