refactor(core): remove style sanitization code for `[style]`/`[style.prop]` bindings (#36965)
In 420b9be1c1
all style-based sanitization code was
disabled because modern browsers no longer allow for javascript expressions within
CSS. This patch is a follow-up patch which removes all traces of style sanitization
code (both instructions and runtime logic) for the `[style]` and `[style.prop]` bindings.
PR Close #36965
This commit is contained in:
parent
141fcb95a4
commit
45f4a47286
|
@ -723,8 +723,6 @@ export declare function ɵɵcontentQuery<T>(directiveIndex: number, predicate: T
|
||||||
|
|
||||||
export declare function ɵɵCopyDefinitionFeature(definition: ɵDirectiveDef<any> | ɵComponentDef<any>): void;
|
export declare function ɵɵCopyDefinitionFeature(definition: ɵDirectiveDef<any> | ɵComponentDef<any>): void;
|
||||||
|
|
||||||
export declare const ɵɵdefaultStyleSanitizer: StyleSanitizeFn;
|
|
||||||
|
|
||||||
export declare function ɵɵdefineComponent<T>(componentDefinition: {
|
export declare function ɵɵdefineComponent<T>(componentDefinition: {
|
||||||
type: Type<T>;
|
type: Type<T>;
|
||||||
selectors?: ɵCssSelectorList;
|
selectors?: ɵCssSelectorList;
|
||||||
|
@ -1050,8 +1048,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 ɵɵ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<any> | null, decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor): void;
|
export declare function ɵɵtemplate(index: number, templateFn: ComponentTemplate<any> | null, decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor): void;
|
||||||
|
|
||||||
export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: ɵangular_packages_core_core_bo): TemplateRef<unknown> | null;
|
export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: ɵangular_packages_core_core_bo): TemplateRef<unknown> | null;
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 2987,
|
"runtime-es2015": 2987,
|
||||||
"main-es2015": 453518,
|
"main-es2015": 452717,
|
||||||
"polyfills-es2015": 52195
|
"polyfills-es2015": 52628
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -555,7 +555,7 @@ describe('compiler compliance: styling', () => {
|
||||||
$r3$.ɵɵelement(0, "div");
|
$r3$.ɵɵelement(0, "div");
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵɵstyleProp("background-image", ctx.myImage, $r3$.ɵɵdefaultStyleSanitizer);
|
$r3$.ɵɵstyleProp("background-image", ctx.myImage);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
encapsulation: 2
|
encapsulation: 2
|
||||||
|
@ -1554,8 +1554,8 @@ describe('compiler compliance: styling', () => {
|
||||||
const template = `
|
const template = `
|
||||||
…
|
…
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵɵstylePropInterpolate1("background", "url(", ctx.myUrl1, ")", $r3$.ɵɵdefaultStyleSanitizer);
|
$r3$.ɵɵstylePropInterpolate1("background", "url(", ctx.myUrl1, ")");
|
||||||
$r3$.ɵɵstylePropInterpolate2("border-image", "url(", ctx.myUrl2, ") ", ctx.myRepeat, " auto", $r3$.ɵɵdefaultStyleSanitizer);
|
$r3$.ɵɵstylePropInterpolate2("border-image", "url(", ctx.myUrl2, ") ", ctx.myRepeat, " auto");
|
||||||
$r3$.ɵɵstylePropInterpolate3("box-shadow", "", ctx.myBoxX, " ", ctx.myBoxY, " ", ctx.myBoxWidth, " black");
|
$r3$.ɵɵstylePropInterpolate3("box-shadow", "", ctx.myBoxX, " ", ctx.myBoxY, " ", ctx.myBoxWidth, " black");
|
||||||
}
|
}
|
||||||
…
|
…
|
||||||
|
@ -2036,110 +2036,6 @@ describe('compiler compliance: styling', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('new styling refactor', () => {
|
describe('new styling refactor', () => {
|
||||||
it('should generate a `styleSanitizer` instruction when one or more sanitizable style properties are statically detected',
|
|
||||||
() => {
|
|
||||||
const files = {
|
|
||||||
app: {
|
|
||||||
'spec.ts': `
|
|
||||||
import {Component, NgModule} from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
template: \`
|
|
||||||
<div [style.background-image]="bgExp"></div>
|
|
||||||
\`
|
|
||||||
})
|
|
||||||
export class MyAppComp {
|
|
||||||
bgExp = '';
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const template = `
|
|
||||||
template: function MyAppComp_Template(rf, ctx) {
|
|
||||||
…
|
|
||||||
if (rf & 2) {
|
|
||||||
$r3$.ɵɵstyleProp("background-image", ctx.bgExp, $r3$.ɵɵdefaultStyleSanitizer);
|
|
||||||
}
|
|
||||||
…
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
|
||||||
expectEmit(result.source, template, 'Incorrect template');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate a `styleSanitizer` instruction when a `styleMap` instruction is used',
|
|
||||||
() => {
|
|
||||||
const files = {
|
|
||||||
app: {
|
|
||||||
'spec.ts': `
|
|
||||||
import {Component, NgModule} from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
template: \`
|
|
||||||
<div [style]="mapExp"></div>
|
|
||||||
\`
|
|
||||||
})
|
|
||||||
export class MyAppComp {
|
|
||||||
mapExp = {};
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const template = `
|
|
||||||
template: function MyAppComp_Template(rf, ctx) {
|
|
||||||
…
|
|
||||||
if (rf & 2) {
|
|
||||||
$r3$.ɵɵstyleMap(ctx.mapExp);
|
|
||||||
}
|
|
||||||
…
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
|
||||||
expectEmit(result.source, template, 'Incorrect template');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('shouldn\'t generate a `styleSanitizer` instruction when class-based instructions are used',
|
|
||||||
() => {
|
|
||||||
const files = {
|
|
||||||
app: {
|
|
||||||
'spec.ts': `
|
|
||||||
import {Component, NgModule} from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'my-app',
|
|
||||||
template: \`
|
|
||||||
<div [class]="mapExp" [class.name]="nameExp"></div>
|
|
||||||
\`
|
|
||||||
})
|
|
||||||
export class MyAppComp {
|
|
||||||
mapExp = {};
|
|
||||||
nameExp = true;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const template = `
|
|
||||||
template: function MyAppComp_Template(rf, ctx) {
|
|
||||||
…
|
|
||||||
if (rf & 2) {
|
|
||||||
$r3$.ɵɵclassMap(ctx.mapExp);
|
|
||||||
$r3$.ɵɵclassProp("name", ctx.nameExp);
|
|
||||||
}
|
|
||||||
…
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = compile(files, angularFiles);
|
|
||||||
expectEmit(result.source, template, 'Incorrect template');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should generate the correct amount of host bindings when styling is present', () => {
|
it('should generate the correct amount of host bindings when styling is present', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
|
|
|
@ -315,8 +315,6 @@ export class Identifiers {
|
||||||
// sanitization-related functions
|
// sanitization-related functions
|
||||||
static sanitizeHtml: o.ExternalReference = {name: 'ɵɵsanitizeHtml', moduleName: CORE};
|
static sanitizeHtml: o.ExternalReference = {name: 'ɵɵsanitizeHtml', moduleName: CORE};
|
||||||
static sanitizeStyle: o.ExternalReference = {name: 'ɵɵsanitizeStyle', moduleName: CORE};
|
static sanitizeStyle: o.ExternalReference = {name: 'ɵɵsanitizeStyle', moduleName: CORE};
|
||||||
static defaultStyleSanitizer:
|
|
||||||
o.ExternalReference = {name: 'ɵɵdefaultStyleSanitizer', moduleName: CORE};
|
|
||||||
static sanitizeResourceUrl:
|
static sanitizeResourceUrl:
|
||||||
o.ExternalReference = {name: 'ɵɵsanitizeResourceUrl', moduleName: CORE};
|
o.ExternalReference = {name: 'ɵɵsanitizeResourceUrl', moduleName: CORE};
|
||||||
static sanitizeScript: o.ExternalReference = {name: 'ɵɵsanitizeScript', moduleName: CORE};
|
static sanitizeScript: o.ExternalReference = {name: 'ɵɵsanitizeScript', moduleName: CORE};
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* 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 {ConstantPool} from '../../constant_pool';
|
|
||||||
import {AttributeMarker} from '../../core';
|
import {AttributeMarker} from '../../core';
|
||||||
import {AST, ASTWithSource, BindingPipe, BindingType, Interpolation} from '../../expression_parser/ast';
|
import {AST, ASTWithSource, BindingPipe, BindingType, Interpolation} from '../../expression_parser/ast';
|
||||||
import * as o from '../../output/output_ast';
|
import * as o from '../../output/output_ast';
|
||||||
|
@ -92,9 +91,8 @@ export interface StylingInstructionCall {
|
||||||
interface BoundStylingEntry {
|
interface BoundStylingEntry {
|
||||||
hasOverrideFlag: boolean;
|
hasOverrideFlag: boolean;
|
||||||
name: string|null;
|
name: string|null;
|
||||||
unit: string|null;
|
suffix: string|null;
|
||||||
sourceSpan: ParseSourceSpan;
|
sourceSpan: ParseSourceSpan;
|
||||||
sanitize: boolean;
|
|
||||||
value: AST;
|
value: AST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +215,15 @@ export class StylingBuilder {
|
||||||
|
|
||||||
registerStyleInput(
|
registerStyleInput(
|
||||||
name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan,
|
name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan,
|
||||||
unit?: string|null): BoundStylingEntry|null {
|
suffix?: string|null): BoundStylingEntry|null {
|
||||||
if (isEmptyExpression(value)) {
|
if (isEmptyExpression(value)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
name = normalizePropName(name);
|
name = normalizePropName(name);
|
||||||
const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name);
|
const {property, hasOverrideFlag, suffix: bindingSuffix} = parseProperty(name);
|
||||||
const entry: BoundStylingEntry = {
|
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
||||||
name: property,
|
const entry:
|
||||||
sanitize: property ? isStyleSanitizable(property) : true,
|
BoundStylingEntry = {name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag};
|
||||||
unit: unit || bindingUnit,
|
|
||||||
value,
|
|
||||||
sourceSpan,
|
|
||||||
hasOverrideFlag
|
|
||||||
};
|
|
||||||
if (isMapBased) {
|
if (isMapBased) {
|
||||||
this._styleMapInput = entry;
|
this._styleMapInput = entry;
|
||||||
} else {
|
} else {
|
||||||
|
@ -250,8 +243,8 @@ export class StylingBuilder {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const {property, hasOverrideFlag} = parseProperty(name);
|
const {property, hasOverrideFlag} = parseProperty(name);
|
||||||
const entry: BoundStylingEntry =
|
const entry:
|
||||||
{name: property, value, sourceSpan, sanitize: false, hasOverrideFlag, unit: null};
|
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, suffix: null};
|
||||||
if (isMapBased) {
|
if (isMapBased) {
|
||||||
if (this._classMapInput) {
|
if (this._classMapInput) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -430,7 +423,7 @@ export class StylingBuilder {
|
||||||
allocateBindingSlots: totalBindingSlotsRequired,
|
allocateBindingSlots: totalBindingSlotsRequired,
|
||||||
supportsInterpolation: !!getInterpolationExpressionFn,
|
supportsInterpolation: !!getInterpolationExpressionFn,
|
||||||
params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
|
params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
|
||||||
// params => stylingProp(propName, value, suffix|sanitizer)
|
// params => stylingProp(propName, value, suffix)
|
||||||
const params: o.Expression[] = [];
|
const params: o.Expression[] = [];
|
||||||
params.push(o.literal(input.name));
|
params.push(o.literal(input.name));
|
||||||
|
|
||||||
|
@ -441,16 +434,10 @@ export class StylingBuilder {
|
||||||
params.push(convertResult);
|
params.push(convertResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
// [style.prop] bindings may use suffix values (e.g. px, em, etc...) and they
|
// [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
|
||||||
// can also use a sanitizer. Sanitization occurs for url-based entries. Having
|
// if that is detected then we need to pass that in as an optional param.
|
||||||
// the suffix value and a sanitizer together into the instruction doesn't make
|
if (!isClassBased && input.suffix !== null) {
|
||||||
// any sense (url-based entries cannot be sanitized).
|
params.push(o.literal(input.suffix));
|
||||||
if (!isClassBased) {
|
|
||||||
if (input.unit) {
|
|
||||||
params.push(o.literal(input.unit));
|
|
||||||
} else if (input.sanitize) {
|
|
||||||
params.push(o.importExpr(R3.defaultStyleSanitizer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
|
@ -517,27 +504,8 @@ function registerIntoMap(map: Map<string, number>, key: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isStyleSanitizable(prop: string): boolean {
|
|
||||||
// Note that browsers support both the dash case and
|
|
||||||
// camel case property names when setting through JS.
|
|
||||||
return prop === 'background-image' || prop === 'backgroundImage' || prop === 'background' ||
|
|
||||||
prop === 'border-image' || prop === 'borderImage' || prop === 'border-image-source' ||
|
|
||||||
prop === 'borderImageSource' || prop === 'filter' || prop === 'list-style' ||
|
|
||||||
prop === 'listStyle' || prop === 'list-style-image' || prop === 'listStyleImage' ||
|
|
||||||
prop === 'clip-path' || prop === 'clipPath';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple helper function to either provide the constant literal that will house the value
|
|
||||||
* here or a null value if the provided values are empty.
|
|
||||||
*/
|
|
||||||
function getConstantLiteralFromArray(
|
|
||||||
constantPool: ConstantPool, values: o.Expression[]): o.Expression {
|
|
||||||
return values.length ? constantPool.getConstLiteral(o.literalArr(values), true) : o.NULL_EXPR;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseProperty(name: string):
|
export function parseProperty(name: string):
|
||||||
{property: string, unit: string, hasOverrideFlag: boolean} {
|
{property: string, suffix: string|null, hasOverrideFlag: boolean} {
|
||||||
let hasOverrideFlag = false;
|
let hasOverrideFlag = false;
|
||||||
const overrideIndex = name.indexOf(IMPORTANT_FLAG);
|
const overrideIndex = name.indexOf(IMPORTANT_FLAG);
|
||||||
if (overrideIndex !== -1) {
|
if (overrideIndex !== -1) {
|
||||||
|
@ -545,15 +513,15 @@ export function parseProperty(name: string):
|
||||||
hasOverrideFlag = true;
|
hasOverrideFlag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let unit = '';
|
let suffix: string|null = null;
|
||||||
let property = name;
|
let property = name;
|
||||||
const unitIndex = name.lastIndexOf('.');
|
const unitIndex = name.lastIndexOf('.');
|
||||||
if (unitIndex > 0) {
|
if (unitIndex > 0) {
|
||||||
unit = name.substr(unitIndex + 1);
|
suffix = name.substr(unitIndex + 1);
|
||||||
property = name.substring(0, unitIndex);
|
property = name.substring(0, unitIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {property, unit, hasOverrideFlag};
|
return {property, suffix, hasOverrideFlag};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -227,7 +227,6 @@ export {
|
||||||
ɵɵstylePropInterpolate7,
|
ɵɵstylePropInterpolate7,
|
||||||
ɵɵstylePropInterpolate8,
|
ɵɵstylePropInterpolate8,
|
||||||
ɵɵstylePropInterpolateV,
|
ɵɵstylePropInterpolateV,
|
||||||
ɵɵstyleSanitizer,
|
|
||||||
ɵɵtemplate,
|
ɵɵtemplate,
|
||||||
ɵɵtemplateRefExtractor,
|
ɵɵtemplateRefExtractor,
|
||||||
ɵɵtext,
|
ɵɵtext,
|
||||||
|
@ -286,7 +285,6 @@ export {
|
||||||
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
||||||
} from './sanitization/bypass';
|
} from './sanitization/bypass';
|
||||||
export {
|
export {
|
||||||
ɵɵdefaultStyleSanitizer,
|
|
||||||
ɵɵsanitizeHtml,
|
ɵɵsanitizeHtml,
|
||||||
ɵɵsanitizeResourceUrl,
|
ɵɵsanitizeResourceUrl,
|
||||||
ɵɵsanitizeScript,
|
ɵɵsanitizeScript,
|
||||||
|
|
|
@ -113,7 +113,6 @@ export {
|
||||||
ɵɵstylePropInterpolate8,
|
ɵɵstylePropInterpolate8,
|
||||||
ɵɵstylePropInterpolateV,
|
ɵɵstylePropInterpolateV,
|
||||||
|
|
||||||
ɵɵstyleSanitizer,
|
|
||||||
ɵɵtemplate,
|
ɵɵtemplate,
|
||||||
|
|
||||||
ɵɵtext,
|
ɵɵtext,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import {bindingUpdated} from '../bindings';
|
import {bindingUpdated} from '../bindings';
|
||||||
import {SanitizerFn} from '../interfaces/sanitization';
|
import {SanitizerFn} from '../interfaces/sanitization';
|
||||||
import {getLView, getSelectedIndex, getSelectedTNode, getTView, nextBindingIndex} from '../state';
|
import {getLView, getSelectedTNode, getTView, nextBindingIndex} from '../state';
|
||||||
import {elementAttributeInternal, storePropertyBindingMetadata} from './shared';
|
import {elementAttributeInternal, storePropertyBindingMetadata} from './shared';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {SafeValue, unwrapSafeValue} from '../../sanitization/bypass';
|
import {SafeValue, unwrapSafeValue} from '../../sanitization/bypass';
|
||||||
import {stylePropNeedsSanitization, ɵɵsanitizeStyle} from '../../sanitization/sanitization';
|
|
||||||
import {StyleSanitizeFn} from '../../sanitization/style_sanitizer';
|
|
||||||
import {KeyValueArray, keyValueArrayGet, keyValueArraySet} from '../../util/array_utils';
|
import {KeyValueArray, keyValueArrayGet, keyValueArraySet} from '../../util/array_utils';
|
||||||
import {assertDefined, assertEqual, assertLessThan, assertNotEqual, throwError} from '../../util/assert';
|
import {assertDefined, assertEqual, assertLessThan, assertNotEqual, throwError} from '../../util/assert';
|
||||||
import {EMPTY_ARRAY} from '../../util/empty';
|
import {EMPTY_ARRAY} from '../../util/empty';
|
||||||
|
@ -18,11 +16,10 @@ import {bindingUpdated} from '../bindings';
|
||||||
import {DirectiveDef} from '../interfaces/definition';
|
import {DirectiveDef} from '../interfaces/definition';
|
||||||
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||||
import {RElement, Renderer3} from '../interfaces/renderer';
|
import {RElement, Renderer3} from '../interfaces/renderer';
|
||||||
import {SanitizerFn} from '../interfaces/sanitization';
|
|
||||||
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
|
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
|
||||||
import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view';
|
import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view';
|
||||||
import {applyStyling} from '../node_manipulation';
|
import {applyStyling} from '../node_manipulation';
|
||||||
import {getCurrentDirectiveDef, getCurrentStyleSanitizer, getLView, getSelectedIndex, getTView, incrementBindingIndex, setCurrentStyleSanitizer} from '../state';
|
import {getCurrentDirectiveDef, getLView, getSelectedIndex, getTView, incrementBindingIndex} from '../state';
|
||||||
import {insertTStylingBinding} from '../styling/style_binding_list';
|
import {insertTStylingBinding} from '../styling/style_binding_list';
|
||||||
import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser';
|
import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser';
|
||||||
import {NO_CHANGE} from '../tokens';
|
import {NO_CHANGE} from '../tokens';
|
||||||
|
@ -31,26 +28,6 @@ import {getNativeByIndex} from '../util/view_utils';
|
||||||
import {setDirectiveInputsWhichShadowsStyling} from './property';
|
import {setDirectiveInputsWhichShadowsStyling} from './property';
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
* Update a style binding on an element with the provided value.
|
||||||
*
|
*
|
||||||
|
@ -64,8 +41,6 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn|null): void {
|
||||||
* @param prop A valid CSS property.
|
* @param prop A valid CSS property.
|
||||||
* @param value New value to write (`null` or an empty string to remove).
|
* @param value New value to write (`null` or an empty string to remove).
|
||||||
* @param suffix Optional suffix. Used with scalar values to add unit such as `px`.
|
* @param suffix Optional suffix. Used with scalar values to add unit such as `px`.
|
||||||
* Note that when a suffix is provided then the underlying sanitizer will
|
|
||||||
* be ignored.
|
|
||||||
*
|
*
|
||||||
* Note that this will apply the provided style value to the host element if this function is called
|
* Note that this will apply the provided style value to the host element if this function is called
|
||||||
* within a host binding function.
|
* within a host binding function.
|
||||||
|
@ -183,11 +158,11 @@ export function classStringParser(keyValueArray: KeyValueArray<any>, text: strin
|
||||||
*
|
*
|
||||||
* @param prop property name.
|
* @param prop property name.
|
||||||
* @param value binding value.
|
* @param value binding value.
|
||||||
* @param suffixOrSanitizer suffix or sanitization function
|
* @param suffix suffix for the property (e.g. `em` or `px`)
|
||||||
* @param isClassBased `true` if `class` change (`false` if `style`)
|
* @param isClassBased `true` if `class` change (`false` if `style`)
|
||||||
*/
|
*/
|
||||||
export function checkStylingProperty(
|
export function checkStylingProperty(
|
||||||
prop: string, value: any|NO_CHANGE, suffixOrSanitizer: SanitizerFn|string|undefined|null,
|
prop: string, value: any|NO_CHANGE, suffix: string|undefined|null,
|
||||||
isClassBased: boolean): void {
|
isClassBased: boolean): void {
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tView = getTView();
|
const tView = getTView();
|
||||||
|
@ -199,19 +174,10 @@ export function checkStylingProperty(
|
||||||
stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
|
stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
|
||||||
}
|
}
|
||||||
if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
|
if (value !== NO_CHANGE && bindingUpdated(lView, bindingIndex, value)) {
|
||||||
// This is a work around. Once PR#34480 lands the sanitizer is passed explicitly and this line
|
|
||||||
// can be removed.
|
|
||||||
let styleSanitizer: StyleSanitizeFn|null;
|
|
||||||
if (suffixOrSanitizer == null) {
|
|
||||||
if (styleSanitizer = getCurrentStyleSanitizer()) {
|
|
||||||
suffixOrSanitizer = styleSanitizer as any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
const tNode = tView.data[getSelectedIndex() + HEADER_OFFSET] as TNode;
|
||||||
updateStyling(
|
updateStyling(
|
||||||
tView, tNode, lView, lView[RENDERER], prop,
|
tView, tNode, lView, lView[RENDERER], prop,
|
||||||
lView[bindingIndex + 1] = normalizeAndApplySuffixOrSanitizer(value, suffixOrSanitizer),
|
lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
|
||||||
isClassBased, bindingIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,9 +185,7 @@ export function checkStylingProperty(
|
||||||
* Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
|
* Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
|
||||||
*
|
*
|
||||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||||
* function so that
|
* function so that `style` can be processed. This is done for tree shaking purposes.
|
||||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
|
||||||
* purposes.
|
|
||||||
* @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
|
* @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
|
||||||
* have different parsers.)
|
* have different parsers.)
|
||||||
* @param value bound value from application
|
* @param value bound value from application
|
||||||
|
@ -605,9 +569,8 @@ function collectStylingFromTAttrs(
|
||||||
* keep additional `Map` to keep track of duplicates or items which have not yet been visited.
|
* keep additional `Map` to keep track of duplicates or items which have not yet been visited.
|
||||||
*
|
*
|
||||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||||
* function so that
|
* function so that `style` can be processed. This is done
|
||||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
* for tree shaking purposes.
|
||||||
* purposes.
|
|
||||||
* @param stringParser The parser is passed in so that it will be tree shakable. See
|
* @param stringParser The parser is passed in so that it will be tree shakable. See
|
||||||
* `styleStringParser` and `classStringParser`
|
* `styleStringParser` and `classStringParser`
|
||||||
* @param value The value to parse/convert to `KeyValueArray`
|
* @param value The value to parse/convert to `KeyValueArray`
|
||||||
|
@ -639,19 +602,16 @@ export function toStylingKeyValueArray(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a `value` for a `key` taking style sanitization into account.
|
* Set a `value` for a `key`.
|
||||||
*
|
*
|
||||||
* See: `keyValueArraySet` for details
|
* See: `keyValueArraySet` for details
|
||||||
*
|
*
|
||||||
* @param keyValueArray KeyValueArray to add to.
|
* @param keyValueArray KeyValueArray to add to.
|
||||||
* @param key Style key to add. (This key will be checked if it needs sanitization)
|
* @param key Style key to add.
|
||||||
* @param value The value to set (If key needs sanitization it will be sanitized)
|
* @param value The value to set.
|
||||||
*/
|
*/
|
||||||
export function styleKeyValueArraySet(keyValueArray: KeyValueArray<any>, key: string, value: any) {
|
export function styleKeyValueArraySet(keyValueArray: KeyValueArray<any>, key: string, value: any) {
|
||||||
if (stylePropNeedsSanitization(key)) {
|
keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
|
||||||
value = ɵɵsanitizeStyle(value);
|
|
||||||
}
|
|
||||||
keyValueArraySet(keyValueArray, key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -784,10 +744,7 @@ function updateStyling(
|
||||||
* NOTE: The styling stores two values.
|
* NOTE: The styling stores two values.
|
||||||
* 1. The raw value which came from the application is stored at `index + 0` location. (This value
|
* 1. The raw value which came from the application is stored at `index + 0` location. (This value
|
||||||
* is used for dirty checking).
|
* is used for dirty checking).
|
||||||
* 2. The normalized value (converted to `KeyValueArray` if map and sanitized) is stored at `index +
|
* 2. The normalized value is stored at `index + 1`.
|
||||||
* 1`.
|
|
||||||
* The advantage of storing the sanitized value is that once the value is written we don't need
|
|
||||||
* to worry about sanitizing it later or keeping track of the sanitizer.
|
|
||||||
*
|
*
|
||||||
* @param tData `TData` used for traversing the priority.
|
* @param tData `TData` used for traversing the priority.
|
||||||
* @param tNode `TNode` to use for resolving static styling. Also controls search direction.
|
* @param tNode `TNode` to use for resolving static styling. Also controls search direction.
|
||||||
|
@ -867,22 +824,17 @@ function isStylingValuePresent(value: any): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes or adds suffix to the value.
|
* Normalizes and/or adds a suffix to the value.
|
||||||
*
|
*
|
||||||
* If value is `null`/`undefined` no suffix is added
|
* If value is `null`/`undefined` no suffix is added
|
||||||
* @param value
|
* @param value
|
||||||
* @param suffixOrSanitizer
|
* @param suffix
|
||||||
*/
|
*/
|
||||||
function normalizeAndApplySuffixOrSanitizer(
|
function normalizeSuffix(value: any, suffix: string|undefined|null): string|null|undefined|boolean {
|
||||||
value: any, suffixOrSanitizer: SanitizerFn|string|undefined|null): string|null|undefined|
|
|
||||||
boolean {
|
|
||||||
if (value == null /** || value === undefined */) {
|
if (value == null /** || value === undefined */) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else if (typeof suffixOrSanitizer === 'function') {
|
} else if (typeof suffix === 'string') {
|
||||||
// sanitize the value.
|
value = value + suffix;
|
||||||
value = suffixOrSanitizer(value);
|
|
||||||
} else if (typeof suffixOrSanitizer === 'string') {
|
|
||||||
value = value + suffixOrSanitizer;
|
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
value = stringify(unwrapSafeValue(value));
|
value = stringify(unwrapSafeValue(value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||||
'ɵɵstylePropInterpolate7': r3.ɵɵstylePropInterpolate7,
|
'ɵɵstylePropInterpolate7': r3.ɵɵstylePropInterpolate7,
|
||||||
'ɵɵstylePropInterpolate8': r3.ɵɵstylePropInterpolate8,
|
'ɵɵstylePropInterpolate8': r3.ɵɵstylePropInterpolate8,
|
||||||
'ɵɵstylePropInterpolateV': r3.ɵɵstylePropInterpolateV,
|
'ɵɵstylePropInterpolateV': r3.ɵɵstylePropInterpolateV,
|
||||||
'ɵɵstyleSanitizer': r3.ɵɵstyleSanitizer,
|
|
||||||
'ɵɵclassProp': r3.ɵɵclassProp,
|
'ɵɵclassProp': r3.ɵɵclassProp,
|
||||||
'ɵɵselect': r3.ɵɵselect,
|
'ɵɵselect': r3.ɵɵselect,
|
||||||
'ɵɵadvance': r3.ɵɵadvance,
|
'ɵɵadvance': r3.ɵɵadvance,
|
||||||
|
@ -164,7 +163,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||||
|
|
||||||
'ɵɵsanitizeHtml': sanitization.ɵɵsanitizeHtml,
|
'ɵɵsanitizeHtml': sanitization.ɵɵsanitizeHtml,
|
||||||
'ɵɵsanitizeStyle': sanitization.ɵɵsanitizeStyle,
|
'ɵɵsanitizeStyle': sanitization.ɵɵsanitizeStyle,
|
||||||
'ɵɵdefaultStyleSanitizer': sanitization.ɵɵdefaultStyleSanitizer,
|
|
||||||
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
||||||
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
||||||
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
|
||||||
import {assertDefined, assertEqual} from '../util/assert';
|
import {assertDefined, assertEqual} from '../util/assert';
|
||||||
import {assertLViewOrUndefined} from './assert';
|
import {assertLViewOrUndefined} from './assert';
|
||||||
import {DirectiveDef} from './interfaces/definition';
|
import {DirectiveDef} from './interfaces/definition';
|
||||||
|
@ -97,11 +96,6 @@ interface LFrame {
|
||||||
*/
|
*/
|
||||||
currentNamespace: string|null;
|
currentNamespace: string|null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Current sanitizer
|
|
||||||
*/
|
|
||||||
currentSanitizer: StyleSanitizeFn|null;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root index from which pure function instructions should calculate their binding
|
* The root index from which pure function instructions should calculate their binding
|
||||||
|
@ -421,7 +415,6 @@ export function enterView(newView: LView, tNode: TNode|null): void {
|
||||||
assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
|
assertEqual(newLFrame.elementDepthCount, 0, 'Expected clean LFrame');
|
||||||
assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
|
assertEqual(newLFrame.currentDirectiveIndex, -1, 'Expected clean LFrame');
|
||||||
assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
|
assertEqual(newLFrame.currentNamespace, null, 'Expected clean LFrame');
|
||||||
assertEqual(newLFrame.currentSanitizer, null, 'Expected clean LFrame');
|
|
||||||
assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
|
assertEqual(newLFrame.bindingRootIndex, -1, 'Expected clean LFrame');
|
||||||
assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
|
assertEqual(newLFrame.currentQueryIndex, 0, 'Expected clean LFrame');
|
||||||
}
|
}
|
||||||
|
@ -454,7 +447,6 @@ function createLFrame(parent: LFrame|null): LFrame {
|
||||||
contextLView: null!, //
|
contextLView: null!, //
|
||||||
elementDepthCount: 0, //
|
elementDepthCount: 0, //
|
||||||
currentNamespace: null, //
|
currentNamespace: null, //
|
||||||
currentSanitizer: null, //
|
|
||||||
currentDirectiveIndex: -1, //
|
currentDirectiveIndex: -1, //
|
||||||
bindingRootIndex: -1, //
|
bindingRootIndex: -1, //
|
||||||
bindingIndex: -1, //
|
bindingIndex: -1, //
|
||||||
|
@ -508,7 +500,6 @@ export function leaveView() {
|
||||||
oldLFrame.elementDepthCount = 0;
|
oldLFrame.elementDepthCount = 0;
|
||||||
oldLFrame.currentDirectiveIndex = -1;
|
oldLFrame.currentDirectiveIndex = -1;
|
||||||
oldLFrame.currentNamespace = null;
|
oldLFrame.currentNamespace = null;
|
||||||
oldLFrame.currentSanitizer = null;
|
|
||||||
oldLFrame.bindingRootIndex = -1;
|
oldLFrame.bindingRootIndex = -1;
|
||||||
oldLFrame.bindingIndex = -1;
|
oldLFrame.bindingIndex = -1;
|
||||||
oldLFrame.currentQueryIndex = 0;
|
oldLFrame.currentQueryIndex = 0;
|
||||||
|
@ -602,18 +593,3 @@ export function namespaceHTMLInternal() {
|
||||||
export function getNamespace(): string|null {
|
export function getNamespace(): string|null {
|
||||||
return instructionState.lFrame.currentNamespace;
|
return instructionState.lFrame.currentNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCurrentStyleSanitizer(sanitizer: StyleSanitizeFn|null) {
|
|
||||||
instructionState.lFrame.currentSanitizer = sanitizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetCurrentStyleSanitizer() {
|
|
||||||
setCurrentStyleSanitizer(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCurrentStyleSanitizer() {
|
|
||||||
// TODO(misko): This should throw when there is no LView, but it turns out we can get here from
|
|
||||||
// `NodeStyleDebug` hence we return `null`. This should be fixed
|
|
||||||
const lFrame = instructionState.lFrame;
|
|
||||||
return lFrame === null ? null : lFrame.currentSanitizer;
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import {allowSanitizationBypassAndThrow, BypassType, unwrapSafeValue} from './by
|
||||||
import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer';
|
import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer';
|
||||||
import {Sanitizer} from './sanitizer';
|
import {Sanitizer} from './sanitizer';
|
||||||
import {SecurityContext} from './security';
|
import {SecurityContext} from './security';
|
||||||
import {StyleSanitizeFn, StyleSanitizeMode} from './style_sanitizer';
|
|
||||||
import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer';
|
import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer';
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,47 +175,6 @@ export function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl: any, tag: string, prop:
|
||||||
return getUrlSanitizer(tag, prop)(unsafeUrl);
|
return getUrlSanitizer(tag, prop)(unsafeUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The default style sanitizer will handle sanitization for style properties.
|
|
||||||
*
|
|
||||||
* Style sanitization is no longer apart of Angular because modern browsers no
|
|
||||||
* longer support javascript expressions. Therefore, the reason why this API
|
|
||||||
* exists is exclusively for unwrapping any style value expressions that were
|
|
||||||
* marked as `SafeValue` values.
|
|
||||||
*
|
|
||||||
* This API will be removed in a future release of Angular.
|
|
||||||
*
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export const ɵɵdefaultStyleSanitizer =
|
|
||||||
(function(prop: string, value: string|null, mode?: StyleSanitizeMode): string|boolean|null {
|
|
||||||
if (value === undefined && mode === undefined) {
|
|
||||||
// This is a workaround for the fact that `StyleSanitizeFn` should not exist once PR#34480
|
|
||||||
// lands. For now the `StyleSanitizeFn` and should act like `(value: any) => string` as a
|
|
||||||
// work around.
|
|
||||||
return ɵɵsanitizeStyle(prop);
|
|
||||||
}
|
|
||||||
mode = mode || StyleSanitizeMode.ValidateAndSanitize;
|
|
||||||
let doSanitizeValue = true;
|
|
||||||
if (mode & StyleSanitizeMode.ValidateProperty) {
|
|
||||||
doSanitizeValue = stylePropNeedsSanitization(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode & StyleSanitizeMode.SanitizeOnly) {
|
|
||||||
return doSanitizeValue ? ɵɵsanitizeStyle(value) : unwrapSafeValue(value);
|
|
||||||
} else {
|
|
||||||
return doSanitizeValue;
|
|
||||||
}
|
|
||||||
} as StyleSanitizeFn);
|
|
||||||
|
|
||||||
export function stylePropNeedsSanitization(prop: string): boolean {
|
|
||||||
return prop === 'background-image' || prop === 'backgroundImage' || prop === 'background' ||
|
|
||||||
prop === 'border-image' || prop === 'borderImage' || prop === 'border-image-source' ||
|
|
||||||
prop === 'borderImageSource' || prop === 'filter' || prop === 'list-style' ||
|
|
||||||
prop === 'listStyle' || prop === 'list-style-image' || prop === 'listStyleImage' ||
|
|
||||||
prop === 'clip-path' || prop === 'clipPath';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function validateAgainstEventProperties(name: string) {
|
export function validateAgainstEventProperties(name: string) {
|
||||||
if (name.toLowerCase().startsWith('on')) {
|
if (name.toLowerCase().startsWith('on')) {
|
||||||
const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
|
const msg = `Binding to event property '${name}' is disallowed for security reasons, ` +
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/**
|
|
||||||
* @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 {SafeValue} from './bypass';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ========== WARNING ==========
|
|
||||||
*
|
|
||||||
* Style sanitization in Angular (for `[style.prop]` and `[style]` bindings)
|
|
||||||
* is no longer required and has been removed. The reason why this feature
|
|
||||||
* has been removed is because style-based sanitization is no longer
|
|
||||||
* required with modern browsers.
|
|
||||||
*
|
|
||||||
* The contents of this file are still in flux. Various APIs and symbols will
|
|
||||||
* be removed in a future version of Angular. Please hold off from modifying this
|
|
||||||
* file for the time being.
|
|
||||||
*
|
|
||||||
* =============================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A series of flags to instruct a style sanitizer to either validate
|
|
||||||
* or sanitize a value.
|
|
||||||
*
|
|
||||||
* Because sanitization is dependent on the style property (i.e. style
|
|
||||||
* sanitization for `width` is much different than for `background-image`)
|
|
||||||
* the sanitization function (e.g. `StyleSanitizerFn`) needs to check a
|
|
||||||
* property value first before it actually sanitizes any values.
|
|
||||||
*
|
|
||||||
* This enum exist to allow a style sanitization function to either only
|
|
||||||
* do validation (check the property to see whether a value will be
|
|
||||||
* sanitized or not) or to sanitize the value (or both).
|
|
||||||
*
|
|
||||||
* @publicApi
|
|
||||||
*/
|
|
||||||
export const enum StyleSanitizeMode {
|
|
||||||
/** Just check to see if the property is required to be sanitized or not */
|
|
||||||
ValidateProperty = 0b01,
|
|
||||||
/** Skip checking the property; just sanitize the value */
|
|
||||||
SanitizeOnly = 0b10,
|
|
||||||
/** Check the property and (if true) then sanitize the value */
|
|
||||||
ValidateAndSanitize = 0b11,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to intercept and sanitize style values before they are written to the renderer.
|
|
||||||
*
|
|
||||||
* This function is designed to be called in two modes. When a value is not provided
|
|
||||||
* then the function will return a boolean whether a property will be sanitized later.
|
|
||||||
* If a value is provided then the sanitized version of that will be returned.
|
|
||||||
*/
|
|
||||||
export interface StyleSanitizeFn {
|
|
||||||
(prop: string, value: string|SafeValue|null, mode?: StyleSanitizeMode): any;
|
|
||||||
}
|
|
|
@ -1880,7 +1880,7 @@ describe('styling', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onlyInIvy('only ivy has [style.prop] support')
|
onlyInIvy('only ivy has [style.prop] support')
|
||||||
.it('should sanitize style values before writing them', () => {
|
.it('should not sanitize style values before writing them', () => {
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<div [style.width]="widthExp"
|
<div [style.width]="widthExp"
|
||||||
|
@ -1914,7 +1914,7 @@ describe('styling', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onlyInIvy('only ivy has [style] support')
|
onlyInIvy('only ivy has [style] support')
|
||||||
.it('should sanitize style values before writing them', () => {
|
.it('should not sanitize style values before writing them', () => {
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<div [style.width]="widthExp"
|
<div [style.width]="widthExp"
|
||||||
|
|
|
@ -596,9 +596,6 @@
|
||||||
{
|
{
|
||||||
"name": "getCurrentDirectiveIndex"
|
"name": "getCurrentDirectiveIndex"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "getCurrentStyleSanitizer"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "getDebugContext"
|
"name": "getDebugContext"
|
||||||
},
|
},
|
||||||
|
@ -1017,7 +1014,7 @@
|
||||||
"name": "noSideEffects"
|
"name": "noSideEffects"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "normalizeAndApplySuffixOrSanitizer"
|
"name": "normalizeSuffix"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "readPatchedData"
|
"name": "readPatchedData"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import {DirectiveDef} from '@angular/core/src/render3';
|
import {DirectiveDef} from '@angular/core/src/render3';
|
||||||
import {ɵɵdefineDirective} from '@angular/core/src/render3/definition';
|
import {ɵɵdefineDirective} from '@angular/core/src/render3/definition';
|
||||||
import {classStringParser, styleStringParser, toStylingKeyValueArray, ɵɵclassProp, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer} from '@angular/core/src/render3/instructions/styling';
|
import {classStringParser, styleStringParser, toStylingKeyValueArray, ɵɵclassProp, ɵɵstyleMap, ɵɵstyleProp} from '@angular/core/src/render3/instructions/styling';
|
||||||
import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node';
|
import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node';
|
||||||
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, setTStylingRangeNext, setTStylingRangePrev, StylingRange, toTStylingRange, TStylingKey, TStylingRange} from '@angular/core/src/render3/interfaces/styling';
|
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, setTStylingRangeNext, setTStylingRangePrev, StylingRange, toTStylingRange, TStylingKey, TStylingRange} from '@angular/core/src/render3/interfaces/styling';
|
||||||
import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view';
|
import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view';
|
||||||
|
|
|
@ -10,10 +10,10 @@ import {NgForOfContext} from '@angular/common';
|
||||||
import {getSortedClassName} from '@angular/core/testing/src/styling';
|
import {getSortedClassName} from '@angular/core/testing/src/styling';
|
||||||
|
|
||||||
import {ɵɵdefineComponent} from '../../src/render3/definition';
|
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 {AttributeMarker} from '../../src/render3/interfaces/node';
|
||||||
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, SafeValue, unwrapSafeValue} from '../../src/sanitization/bypass';
|
import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, SafeValue, unwrapSafeValue} from '../../src/sanitization/bypass';
|
||||||
import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization';
|
import {ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization';
|
||||||
import {Sanitizer} from '../../src/sanitization/sanitizer';
|
import {Sanitizer} from '../../src/sanitization/sanitizer';
|
||||||
import {SecurityContext} from '../../src/sanitization/security';
|
import {SecurityContext} from '../../src/sanitization/security';
|
||||||
|
|
||||||
|
@ -170,7 +170,6 @@ describe('instructions', () => {
|
||||||
return createDiv();
|
return createDiv();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer);
|
|
||||||
ɵɵstyleProp('background-image', backgroundImage);
|
ɵɵstyleProp('background-image', backgroundImage);
|
||||||
},
|
},
|
||||||
2, 2);
|
2, 2);
|
||||||
|
@ -199,35 +198,6 @@ describe('instructions', () => {
|
||||||
fixture.update();
|
fixture.update();
|
||||||
expect(fixture.html).toEqual('<div style="background-color: red; height: 10px;"></div>');
|
expect(fixture.html).toEqual('<div style="background-color: red; height: 10px;"></div>');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should sanitize new styles that may contain `url` properties', () => {
|
|
||||||
const detectedValues: string[] = [];
|
|
||||||
const sanitizerInterceptor = new MockSanitizerInterceptor(value => {
|
|
||||||
detectedValues.push(value);
|
|
||||||
});
|
|
||||||
const fixture = new TemplateFixture(
|
|
||||||
() => {
|
|
||||||
return createDiv();
|
|
||||||
}, //
|
|
||||||
() => {
|
|
||||||
ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer());
|
|
||||||
ɵɵstyleMap({
|
|
||||||
'background-image': 'background-image',
|
|
||||||
'background': 'background',
|
|
||||||
'border-image': 'border-image',
|
|
||||||
'list-style': 'list-style',
|
|
||||||
'list-style-image': 'list-style-image',
|
|
||||||
'filter': 'filter',
|
|
||||||
'width': 'width'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
1, 2, null, null, sanitizerInterceptor);
|
|
||||||
|
|
||||||
const props = detectedValues.sort();
|
|
||||||
expect(props).toEqual([
|
|
||||||
'background', 'background-image', 'border-image', 'filter', 'list-style', 'list-style-image'
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('elementClass', () => {
|
describe('elementClass', () => {
|
||||||
|
@ -559,9 +529,6 @@ class LocalMockSanitizer implements Sanitizer {
|
||||||
class MockSanitizerInterceptor {
|
class MockSanitizerInterceptor {
|
||||||
public lastValue: string|null = null;
|
public lastValue: string|null = null;
|
||||||
constructor(private _interceptorFn?: ((value: any) => any)|null) {}
|
constructor(private _interceptorFn?: ((value: any) => any)|null) {}
|
||||||
getStyleSanitizer() {
|
|
||||||
return ɵɵdefaultStyleSanitizer;
|
|
||||||
}
|
|
||||||
sanitize(context: SecurityContext, value: LocalSanitizedValue|string|null|any): string|null {
|
sanitize(context: SecurityContext, value: LocalSanitizedValue|string|null|any): string|null {
|
||||||
if (this._interceptorFn) {
|
if (this._interceptorFn) {
|
||||||
this._interceptorFn(value);
|
this._interceptorFn(value);
|
||||||
|
|
Loading…
Reference in New Issue