diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
index 46083c897c..9143b0a86b 100644
--- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts
@@ -377,7 +377,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelement(0, "div");
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap($ctx$.myStyleExp);
}
}
@@ -511,7 +510,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelement(0, "div", 0);
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap($ctx$.myStyleExp);
$r3$.ɵɵstyleProp("width", $ctx$.myWidth)("height", $ctx$.myHeight);
$r3$.ɵɵattribute("style", "border-width: 10px", $r3$.ɵɵsanitizeStyle);
@@ -557,8 +555,7 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelement(0, "div");
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
- $r3$.ɵɵstyleProp("background-image", ctx.myImage);
+ $r3$.ɵɵstyleProp("background-image", ctx.myImage, $r3$.ɵɵdefaultStyleSanitizer);
}
},
encapsulation: 2
@@ -816,7 +813,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelement(0, "div");
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap($ctx$.myStyleExp);
$r3$.ɵɵclassMap($ctx$.myClassExp);
}
@@ -858,7 +854,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap($r3$.ɵɵpipeBind1(1, 4, $ctx$.myStyleExp));
$r3$.ɵɵclassMap($r3$.ɵɵpipeBind1(2, 6, $ctx$.myClassExp));
}
@@ -911,7 +906,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelementEnd();
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap($r3$.ɵɵpipeBind2(1, 8, $ctx$.myStyleExp, 1000));
$r3$.ɵɵclassMap($r3$.ɵɵpureFunction0(20, _c0));
$r3$.ɵɵstyleProp("bar", $r3$.ɵɵpipeBind2(2, 11, $ctx$.barExp, 3000))("baz", $r3$.ɵɵpipeBind2(3, 14, $ctx$.bazExp, 4000));
@@ -1017,7 +1011,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelementHostAttrs($e0_attrs$);
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.myStyle);
$r3$.ɵɵclassMap(ctx.myClass);
$r3$.ɵɵstyleProp("color", ctx.myColorProp);
@@ -1075,7 +1068,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵallocHostVars(8);
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.myStyle);
$r3$.ɵɵclassMap(ctx.myClasses);
$r3$.ɵɵstyleProp("height", ctx.myHeightProp, "pt")("width", ctx.myWidthProp);
@@ -1133,7 +1125,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵelement(0, "div");
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.myStyleExp);
$r3$.ɵɵclassMap(ctx.myClassExp);
$r3$.ɵɵstyleProp("height", ctx.myHeightExp);
@@ -1148,7 +1139,6 @@ describe('compiler compliance: styling', () => {
$r3$.ɵɵallocHostVars(6);
}
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.myStyleExp);
$r3$.ɵɵclassMap(ctx.myClassExp);
$r3$.ɵɵstyleProp("width", ctx.myWidthExp);
@@ -1424,6 +1414,46 @@ describe('compiler compliance: styling', () => {
expectEmit(result.source, template, 'Incorrect handling of interpolated style properties');
});
+ it('should generate update instructions for interpolated style properties with a sanitizer',
+ () => {
+ const files = {
+ app: {
+ 'spec.ts': `
+ import {Component} from '@angular/core';
+
+ @Component({
+ template: \`
+
+ \`
+ })
+ export class MyComponent {
+ myUrl1 = '...';
+ myUrl2 = '...';
+ myBoxX = '0px';
+ myBoxY = '0px';
+ myBoxWidth = '100px';
+ myRepeat = 'no-repeat';
+ }
+ `
+ }
+ };
+
+ const template = `
+ …
+ if (rf & 2) {
+ $r3$.ɵɵstylePropInterpolate1("background", "url(", ctx.myUrl1, ")", $r3$.ɵɵdefaultStyleSanitizer);
+ $r3$.ɵɵstylePropInterpolate2("border-image", "url(", ctx.myUrl2, ") ", ctx.myRepeat, " auto", $r3$.ɵɵdefaultStyleSanitizer);
+ $r3$.ɵɵstylePropInterpolate3("box-shadow", "", ctx.myBoxX, " ", ctx.myBoxY, " ", ctx.myBoxWidth, " black");
+ }
+ …
+ `;
+ const result = compile(files, angularFiles);
+
+ expectEmit(result.source, template, 'Incorrect handling of interpolated style properties');
+ });
+
it('should generate update instructions for interpolated style properties with !important',
() => {
const files = {
@@ -1849,7 +1879,6 @@ describe('compiler compliance: styling', () => {
}
if (rf & 2) {
$r3$.ɵɵhostProperty("id", ctx.id)("title", ctx.title);
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.myStyle);
$r3$.ɵɵclassMap(ctx.myClass);
}
@@ -1902,7 +1931,7 @@ describe('compiler compliance: styling', () => {
});
describe('new styling refactor', () => {
- it('should generate a `styleSanitizer` instruction when one or more sanitizable style properties are statically detected',
+ it('should generate a sanitizer value into the instruction when one or more sanitizable style properties are statically detected',
() => {
const files = {
app: {
@@ -1926,8 +1955,7 @@ describe('compiler compliance: styling', () => {
template: function MyAppComp_Template(rf, ctx) {
…
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
- $r3$.ɵɵstyleProp("background-image", ctx.bgExp);
+ $r3$.ɵɵstyleProp("background-image", ctx.bgExp, $r3$.ɵɵdefaultStyleSanitizer);
}
…
}
@@ -1937,11 +1965,10 @@ describe('compiler compliance: styling', () => {
expectEmit(result.source, template, 'Incorrect template');
});
- it('should generate a `styleSanitizer` instruction when a `styleMap` instruction is used',
- () => {
- const files = {
- app: {
- 'spec.ts': `
+ it('should not add a sanitizer param when a `styleMap` instruction is used', () => {
+ const files = {
+ app: {
+ 'spec.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
@@ -1954,25 +1981,24 @@ describe('compiler compliance: styling', () => {
mapExp = {};
}
`
- }
- };
+ }
+ };
- const template = `
+ const template = `
template: function MyAppComp_Template(rf, ctx) {
…
if (rf & 2) {
- $r3$.ɵɵstyleSanitizer($r3$.ɵɵdefaultStyleSanitizer);
$r3$.ɵɵstyleMap(ctx.mapExp);
}
…
}
`;
- const result = compile(files, angularFiles);
- expectEmit(result.source, template, 'Incorrect template');
- });
+ const result = compile(files, angularFiles);
+ expectEmit(result.source, template, 'Incorrect template');
+ });
- it('shouldn\'t generate a `styleSanitizer` instruction when class-based instructions are used',
+ it('shouldn\'t generate a sanitizer param into the styling instruction when class-based instructions are used',
() => {
const files = {
app: {
diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts
index dc43f681a2..06b76c07d0 100644
--- a/packages/compiler/src/render3/r3_identifiers.ts
+++ b/packages/compiler/src/render3/r3_identifiers.ts
@@ -113,8 +113,6 @@ export class Identifiers {
static stylePropInterpolateV:
o.ExternalReference = {name: 'ɵɵstylePropInterpolateV', moduleName: CORE};
- static styleSanitizer: o.ExternalReference = {name: 'ɵɵstyleSanitizer', moduleName: CORE};
-
static elementHostAttrs: o.ExternalReference = {name: 'ɵɵelementHostAttrs', moduleName: CORE};
static containerCreate: o.ExternalReference = {name: 'ɵɵcontainer', moduleName: CORE};
diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts
index 67d546ecab..a85e903335 100644
--- a/packages/compiler/src/render3/view/styling_builder.ts
+++ b/packages/compiler/src/render3/view/styling_builder.ts
@@ -44,6 +44,7 @@ interface BoundStylingEntry {
name: string|null;
unit: string|null;
sourceSpan: ParseSourceSpan;
+ sanitize: boolean;
value: AST;
}
@@ -116,10 +117,6 @@ export class StylingBuilder {
private _initialStyleValues: string[] = [];
private _initialClassValues: string[] = [];
- // certain style properties ALWAYS need sanitization
- // this is checked each time new styles are encountered
- private _useDefaultSanitizer = false;
-
constructor(private _elementIndexExpr: o.Expression, private _directiveExpr: o.Expression|null) {}
/**
@@ -179,14 +176,13 @@ export class StylingBuilder {
const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name);
const entry: BoundStylingEntry = {
name: property,
+ sanitize: property ? isStyleSanitizable(property) : true,
unit: unit || bindingUnit, value, sourceSpan, hasOverrideFlag
};
if (isMapBased) {
- this._useDefaultSanitizer = true;
this._styleMapInput = entry;
} else {
(this._singleStyleInputs = this._singleStyleInputs || []).push(entry);
- this._useDefaultSanitizer = this._useDefaultSanitizer || isStyleSanitizable(name);
registerIntoMap(this._stylesIndex, property);
}
this._lastStylingInput = entry;
@@ -202,8 +198,8 @@ export class StylingBuilder {
return null;
}
const {property, hasOverrideFlag} = parseProperty(name);
- const entry:
- BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, unit: null};
+ const entry: BoundStylingEntry =
+ {name: property, value, sourceSpan, sanitize: false, hasOverrideFlag, unit: null};
if (isMapBased) {
if (this._classMapInput) {
throw new Error(
@@ -364,10 +360,9 @@ export class StylingBuilder {
}
private _buildSingleInputs(
- reference: o.ExternalReference, inputs: BoundStylingEntry[], mapIndex: Map,
- allowUnits: boolean, valueConverter: ValueConverter,
- getInterpolationExpressionFn?: (value: Interpolation) => o.ExternalReference):
- StylingInstruction[] {
+ reference: o.ExternalReference, inputs: BoundStylingEntry[], valueConverter: ValueConverter,
+ getInterpolationExpressionFn: ((value: Interpolation) => o.ExternalReference)|null,
+ isClassBased: boolean): StylingInstruction[] {
const instructions: StylingInstruction[] = [];
inputs.forEach(input => {
@@ -390,7 +385,7 @@ export class StylingBuilder {
allocateBindingSlots: totalBindingSlotsRequired,
supportsInterpolation: !!getInterpolationExpressionFn,
params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
- // params => stylingProp(propName, value)
+ // params => stylingProp(propName, value, suffix|sanitizer)
const params: o.Expression[] = [];
params.push(o.literal(input.name));
@@ -401,8 +396,16 @@ export class StylingBuilder {
params.push(convertResult);
}
- if (allowUnits && input.unit) {
- params.push(o.literal(input.unit));
+ // [style.prop] bindings may use suffix values (e.g. px, em, etc...) and they
+ // can also use a sanitizer. Sanitization occurs for url-based entries. Having
+ // the suffix value and a sanitizer together into the instruction doesn't make
+ // any sense (url-based entries cannot be sanitized).
+ if (!isClassBased) {
+ if (input.unit) {
+ params.push(o.literal(input.unit));
+ } else if (input.sanitize) {
+ params.push(o.importExpr(R3.defaultStyleSanitizer));
+ }
}
return params;
@@ -427,7 +430,7 @@ export class StylingBuilder {
private _buildClassInputs(valueConverter: ValueConverter): StylingInstruction[] {
if (this._singleClassInputs) {
return this._buildSingleInputs(
- R3.classProp, this._singleClassInputs, this._classesIndex, false, valueConverter);
+ R3.classProp, this._singleClassInputs, valueConverter, null, true);
}
return [];
}
@@ -435,23 +438,12 @@ export class StylingBuilder {
private _buildStyleInputs(valueConverter: ValueConverter): StylingInstruction[] {
if (this._singleStyleInputs) {
return this._buildSingleInputs(
- R3.styleProp, this._singleStyleInputs, this._stylesIndex, true, valueConverter,
- getStylePropInterpolationExpression);
+ R3.styleProp, this._singleStyleInputs, valueConverter,
+ getStylePropInterpolationExpression, false);
}
return [];
}
- private _buildSanitizerFn(): StylingInstruction {
- return {
- reference: R3.styleSanitizer,
- calls: [{
- sourceSpan: this._firstStylingInput ? this._firstStylingInput.sourceSpan : null,
- allocateBindingSlots: 0,
- params: () => [o.importExpr(R3.defaultStyleSanitizer)]
- }]
- };
- }
-
/**
* Constructs all instructions which contain the expressions that will be placed
* into the update block of a template function or a directive hostBindings function.
@@ -459,9 +451,6 @@ export class StylingBuilder {
buildUpdateLevelInstructions(valueConverter: ValueConverter) {
const instructions: StylingInstruction[] = [];
if (this.hasBindings) {
- if (this._useDefaultSanitizer) {
- instructions.push(this._buildSanitizerFn());
- }
const styleMapInstruction = this.buildStyleMapInstruction(valueConverter);
if (styleMapInstruction) {
instructions.push(styleMapInstruction);
diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts
index 49beffaba4..bd1fc6186d 100644
--- a/packages/core/src/core_render3_private_export.ts
+++ b/packages/core/src/core_render3_private_export.ts
@@ -122,7 +122,6 @@ export {
ɵɵelementContainerEnd,
ɵɵelementContainer,
ɵɵstyleMap,
- ɵɵstyleSanitizer,
ɵɵclassMap,
ɵɵclassMapInterpolate1,
ɵɵclassMapInterpolate2,
diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts
index 7baacc216e..aed5411850 100644
--- a/packages/core/src/render3/index.ts
+++ b/packages/core/src/render3/index.ts
@@ -115,7 +115,6 @@ export {
ɵɵstylePropInterpolate8,
ɵɵstylePropInterpolateV,
- ɵɵstyleSanitizer,
ɵɵtemplate,
ɵɵtext,
diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts
index 68c108bdcf..2f3f556325 100644
--- a/packages/core/src/render3/instructions/styling.ts
+++ b/packages/core/src/render3/instructions/styling.ts
@@ -6,6 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {SafeValue} from '../../sanitization/bypass';
+import {ɵɵdefaultStyleSanitizer} from '../../sanitization/sanitization';
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
import {throwErrorIfNoChangesMode} from '../errors';
import {setInputsForProperty} from '../instructions/shared';
@@ -15,7 +16,7 @@ import {StylingMapArray, StylingMapArrayIndex, TStylingContext} from '../interfa
import {isDirectiveHost} from '../interfaces/type_checks';
import {LView, RENDERER, TVIEW} from '../interfaces/view';
import {getActiveDirectiveId, getCheckNoChangesMode, getCurrentStyleSanitizer, getLView, getSelectedIndex, incrementBindingIndex, nextBindingIndex, resetCurrentStyleSanitizer, setCurrentStyleSanitizer, setElementExitFn} from '../state';
-import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, setClass, setStyle, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
+import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
import {activateStylingMapFeature} from '../styling/map_based_bindings';
import {attachStylingDebugObject} from '../styling/styling_debug';
import {NO_CHANGE} from '../tokens';
@@ -35,26 +36,6 @@ import {getNativeByTNode, getTNode} from '../util/view_utils';
* --------
*/
-/**
- * Sets the current style sanitizer function which will then be used
- * within all follow-up prop and map-based style binding instructions
- * for the given element.
- *
- * Note that once styling has been applied to the element (i.e. once
- * `advance(n)` is executed or the hostBindings/template function exits)
- * then the active `sanitizerFn` will be set to `null`. This means that
- * once styling is applied to another element then a another call to
- * `styleSanitizer` will need to be made.
- *
- * @param sanitizerFn The sanitization function that will be used to
- * process style prop/value entries.
- *
- * @codeGenApi
- */
-export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void {
- setCurrentStyleSanitizer(sanitizer);
-}
-
/**
* Update a style binding on an element with the provided value.
*
@@ -78,8 +59,8 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void {
*/
export function ɵɵstyleProp(
prop: string, value: string | number | SafeValue | null,
- suffix?: string | null): typeof ɵɵstyleProp {
- stylePropInternal(getSelectedIndex(), prop, value, suffix);
+ suffixOrSanitizer?: StyleSanitizeFn | string | null): typeof ɵɵstyleProp {
+ stylePropInternal(getSelectedIndex(), prop, value, suffixOrSanitizer);
return ɵɵstyleProp;
}
@@ -91,7 +72,7 @@ export function ɵɵstyleProp(
*/
export function stylePropInternal(
elementIndex: number, prop: string, value: string | number | SafeValue | null,
- suffix?: string | null | undefined): void {
+ suffixOrSanitizer?: StyleSanitizeFn | string | null): void {
// if a value is interpolated then it may render a `NO_CHANGE` value.
// in this case we do not need to do anything, but the binding index
// still needs to be incremented because all styling binding values
@@ -109,9 +90,12 @@ export function stylePropInternal(
patchHostStylingFlag(tNode, isHostStyling(), false);
}
+ const isString = typeof suffixOrSanitizer === 'string';
+ const suffix = isString ? (suffixOrSanitizer as string) : null;
+ const sanitizer = isString ? null : (suffixOrSanitizer as StyleSanitizeFn | null | undefined);
const updated = stylingProp(
tNode, firstUpdatePass, lView, bindingIndex, prop, resolveStylePropValue(value, suffix),
- false);
+ false, sanitizer);
if (ngDevMode) {
ngDevMode.styleProp++;
if (updated) {
@@ -154,7 +138,8 @@ export function ɵɵclassProp(className: string, value: boolean | null): typeof
patchHostStylingFlag(tNode, isHostStyling(), true);
}
- const updated = stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true);
+ const updated =
+ stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true, null);
if (ngDevMode) {
ngDevMode.classProp++;
if (updated) {
@@ -177,12 +162,15 @@ export function ɵɵclassProp(className: string, value: boolean | null): typeof
function stylingProp(
tNode: TNode, firstUpdatePass: boolean, lView: LView, bindingIndex: number, prop: string,
value: boolean | number | SafeValue | string | null | undefined | NO_CHANGE,
- isClassBased: boolean): boolean {
+ isClassBased: boolean, sanitizer: StyleSanitizeFn | null | undefined): boolean {
let updated = false;
+ if (sanitizer) {
+ setCurrentStyleSanitizer(sanitizer);
+ }
+
const native = getNativeByTNode(tNode, lView) as RElement;
const context = isClassBased ? getClassesContext(tNode) : getStylesContext(tNode);
- const sanitizer = isClassBased ? null : getCurrentStyleSanitizer();
// [style.prop] and [class.name] bindings do not use `bind()` and will
// therefore manage accessing and updating the new value in the lView directly.
@@ -283,7 +271,8 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
}
stylingMap(
- context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput);
+ context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput,
+ ɵɵdefaultStyleSanitizer);
}
/**
@@ -346,7 +335,7 @@ export function classMapInternal(
}
stylingMap(
- context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput);
+ context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput, null);
}
/**
@@ -358,11 +347,11 @@ export function classMapInternal(
function stylingMap(
context: TStylingContext, tNode: TNode, firstUpdatePass: boolean, lView: LView,
bindingIndex: number, value: {[key: string]: any} | string | null, isClassBased: boolean,
- hasDirectiveInput: boolean): void {
+ hasDirectiveInput: boolean, sanitizer: StyleSanitizeFn | null): void {
const directiveIndex = getActiveDirectiveId();
const native = getNativeByTNode(tNode, lView) as RElement;
const oldValue = getValue(lView, bindingIndex);
- const sanitizer = getCurrentStyleSanitizer();
+ setCurrentStyleSanitizer(ɵɵdefaultStyleSanitizer);
const valueHasChanged = hasValueChanged(oldValue, value);
// [style] and [class] bindings do not use `bind()` and will therefore
diff --git a/packages/core/src/render3/interfaces/styling.ts b/packages/core/src/render3/interfaces/styling.ts
index 04a88399ed..e83f557d81 100644
--- a/packages/core/src/render3/interfaces/styling.ts
+++ b/packages/core/src/render3/interfaces/styling.ts
@@ -297,12 +297,14 @@ import {LView} from './view';
*
* It is enabled in two cases:
*
- * 1. The `styleSanitizer(sanitizerFn)` instruction was called (just before any other
- * styling instructions are run).
+ * 1. One or more styleProp instructions are generated (a sanitizer is passed in to each one).
*
- * 2. The component/directive `LView` instance has a sanitizer object attached to it
- * (this happens when `renderComponent` is executed with a `sanitizer` value or
- * if the ngModule contains a sanitizer provider attached to it).
+ * 2. the `styleMap` instruction runs (it uses it by default internally).
+ *
+ * Sanitization can be enabled in the cases above, however, if a sanitizer is attached
+ * in the `LView` then that sanitizer can be used to override whatever sanitizer is
+ * passed in the examples above (this happens when `renderComponent` is executed with a
+ * `sanitizer` value or if the ngModule contains a sanitizer provider attached to it).
*
* If and when sanitization is active then all property/value entries will be evaluated
* through the active sanitizer before they are applied to the element (or the styling
@@ -310,18 +312,6 @@ import {LView} from './view';
*
* If a `Sanitizer` object is used (via the `LView[SANITIZER]` value) then that object
* will be used for every property.
- *
- * If a `StyleSanitizerFn` function is used (via the `styleSanitizer`) then it will be
- * called in two ways:
- *
- * 1. property validation mode: this will be called early to mark whether a property
- * should be sanitized or not at during the flushing stage.
- *
- * 2. value sanitization mode: this will be called during the flushing stage and will
- * run the sanitizer function against the value before applying it to the element.
- *
- * If sanitization returns an empty value then that empty value will be applied
- * to the element.
*/
export interface TStylingContext extends
Array {
diff --git a/packages/core/src/render3/jit/environment.ts b/packages/core/src/render3/jit/environment.ts
index 5e4612edb2..a2ca0d40d0 100644
--- a/packages/core/src/render3/jit/environment.ts
+++ b/packages/core/src/render3/jit/environment.ts
@@ -129,7 +129,6 @@ export const angularCoreEnv: {[name: string]: Function} =
'ɵɵstylePropInterpolate7': r3.ɵɵstylePropInterpolate7,
'ɵɵstylePropInterpolate8': r3.ɵɵstylePropInterpolate8,
'ɵɵstylePropInterpolateV': r3.ɵɵstylePropInterpolateV,
- 'ɵɵstyleSanitizer': r3.ɵɵstyleSanitizer,
'ɵɵclassProp': r3.ɵɵclassProp,
'ɵɵselect': r3.ɵɵselect,
'ɵɵadvance': r3.ɵɵadvance,
diff --git a/packages/core/src/render3/styling/bindings.ts b/packages/core/src/render3/styling/bindings.ts
index 176f03f050..7c0326dcee 100644
--- a/packages/core/src/render3/styling/bindings.ts
+++ b/packages/core/src/render3/styling/bindings.ts
@@ -97,7 +97,8 @@ export function updateStyleViaContext(
context: TStylingContext, tNode: TStylingNode, data: LStylingData, element: RElement,
directiveIndex: number, prop: string | null, bindingIndex: number,
value: string | number | SafeValue | null | undefined | StylingMapArray | NO_CHANGE,
- sanitizer: StyleSanitizeFn | null, forceUpdate: boolean, firstUpdatePass: boolean): boolean {
+ sanitizer: StyleSanitizeFn | null | undefined, forceUpdate: boolean,
+ firstUpdatePass: boolean): boolean {
const isMapBased = !prop;
const state = getStylingState(element, directiveIndex);
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;
diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts
index be6f6b5fa2..9e06835880 100644
--- a/packages/core/test/render3/instructions_spec.ts
+++ b/packages/core/test/render3/instructions_spec.ts
@@ -9,7 +9,7 @@
import {NgForOfContext} from '@angular/common';
import {ɵɵdefineComponent} from '../../src/render3/definition';
-import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index';
+import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index';
import {AttributeMarker} from '../../src/render3/interfaces/node';
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, unwrapSafeValue} from '../../src/sanitization/bypass';
import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization';
@@ -137,20 +137,22 @@ describe('instructions', () => {
describe('styleProp', () => {
it('should automatically sanitize unless a bypass operation is applied', () => {
- const t = new TemplateFixture(() => { return createDiv(); }, () => {}, 1);
- t.update(() => {
- ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer);
- ɵɵstyleProp('background-image', 'url("http://server")');
- });
- // nothing is set because sanitizer suppresses it.
- expect(t.html).toEqual('');
+ const t = new TemplateFixture(
+ () => { return createDiv(); },
+ () => {
+ ɵɵstyleProp('background-image', 'url("http://server")', ɵɵdefaultStyleSanitizer);
+ },
+ 1);
+
+ const element = t.hostElement.firstChild as HTMLElement;
+ expect(element.style.getPropertyValue('background-image')).toEqual('');
t.update(() => {
- ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer);
- ɵɵstyleProp('background-image', bypassSanitizationTrustStyle('url("http://server2")'));
+ ɵɵstyleProp(
+ 'background-image', bypassSanitizationTrustStyle('url("http://server2")'),
+ ɵɵdefaultStyleSanitizer);
});
- expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image'))
- .toEqual('url("http://server2")');
+ expect(element.style.getPropertyValue('background-image')).toEqual('url("http://server2")');
});
});
@@ -160,10 +162,14 @@ describe('instructions', () => {
function createDivWithStyle() { ɵɵelement(0, 'div', 0); }
it('should add style', () => {
- const fixture = new TemplateFixture(
- createDivWithStyle, () => {}, 1, 0, null, null, null, undefined, attrs);
- fixture.update(() => { ɵɵstyleMap({'background-color': 'red'}); });
- expect(fixture.html).toEqual('');
+ const fixture = new TemplateFixture(createDivWithStyle, () => {
+ ɵɵstyleMap({'background-color': 'red'});
+ }, 1, 0, null, null, null, undefined, attrs);
+ fixture.update();
+ const targetDiv = fixture.hostElement.querySelector('div') !;
+ const style = targetDiv.style as{[key: string]: any};
+ expect(style['background-color']).toEqual('red');
+ expect(style['height']).toEqual('10px');
});
it('should sanitize new styles that may contain `url` properties', () => {
@@ -173,7 +179,6 @@ describe('instructions', () => {
const fixture = new TemplateFixture(
() => { return createDiv(); }, //
() => {
- ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer());
ɵɵstyleMap({
'background-image': 'background-image',
'background': 'background',
diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts
index e2da2d0137..e76b3bd1f5 100644
--- a/tools/public_api_guard/core/core.d.ts
+++ b/tools/public_api_guard/core/core.d.ts
@@ -1037,7 +1037,7 @@ export declare function ɵɵstyleMap(styles: {
[styleName: string]: any;
} | NO_CHANGE | null): void;
-export declare function ɵɵstyleProp(prop: string, value: string | number | SafeValue | null, suffix?: string | null): typeof ɵɵstyleProp;
+export declare function ɵɵstyleProp(prop: string, value: string | number | SafeValue | null, suffixOrSanitizer?: StyleSanitizeFn | string | null): typeof ɵɵstyleProp;
export declare function ɵɵstylePropInterpolate1(prop: string, prefix: string, v0: any, suffix: string, valueSuffix?: string | null): typeof ɵɵstylePropInterpolate1;
@@ -1057,8 +1057,6 @@ export declare function ɵɵstylePropInterpolate8(prop: string, prefix: string,
export declare function ɵɵstylePropInterpolateV(prop: string, values: any[], valueSuffix?: string | null): typeof ɵɵstylePropInterpolateV;
-export declare function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void;
-
export declare function ɵɵtemplate(index: number, templateFn: ComponentTemplate | null, decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor): void;
export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: LView): ViewEngine_TemplateRef | null;