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 const ɵɵdefaultStyleSanitizer: StyleSanitizeFn;
|
||||
|
||||
export declare function ɵɵdefineComponent<T>(componentDefinition: {
|
||||
type: Type<T>;
|
||||
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 ɵɵ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 ɵɵtemplateRefExtractor(tNode: TNode, currentView: ɵangular_packages_core_core_bo): TemplateRef<unknown> | null;
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime-es2015": 2987,
|
||||
"main-es2015": 453518,
|
||||
"polyfills-es2015": 52195
|
||||
"main-es2015": 452717,
|
||||
"polyfills-es2015": 52628
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -555,7 +555,7 @@ describe('compiler compliance: styling', () => {
|
|||
$r3$.ɵɵelement(0, "div");
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵstyleProp("background-image", ctx.myImage, $r3$.ɵɵdefaultStyleSanitizer);
|
||||
$r3$.ɵɵstyleProp("background-image", ctx.myImage);
|
||||
}
|
||||
},
|
||||
encapsulation: 2
|
||||
|
@ -1151,15 +1151,15 @@ describe('compiler compliance: styling', () => {
|
|||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule, HostBinding} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`
|
||||
<div class="A{{p1}}B"></div>
|
||||
<div class="A{{p1}}B{{p2}}C"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E{{p5}}F"></div>
|
||||
<div class="A{{p1}}B{{p2}}C"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E{{p5}}F"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E{{p5}}F{{p6}}G"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E{{p5}}F{{p6}}G{{p7}}H"></div>
|
||||
<div class="A{{p1}}B{{p2}}C{{p3}}D{{p4}}E{{p5}}F{{p6}}G{{p7}}H{{p8}}I"></div>
|
||||
|
@ -1178,7 +1178,7 @@ describe('compiler compliance: styling', () => {
|
|||
p8 = 100;
|
||||
p9 = 100;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
|
@ -1221,7 +1221,7 @@ describe('compiler compliance: styling', () => {
|
|||
app: {
|
||||
'spec.ts': `
|
||||
import {Component, NgModule, HostBinding} from '@angular/core';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
template: \`
|
||||
|
@ -1248,7 +1248,7 @@ describe('compiler compliance: styling', () => {
|
|||
p8 = 100;
|
||||
p9 = 100;
|
||||
}
|
||||
|
||||
|
||||
@NgModule({declarations: [MyComponent]})
|
||||
export class MyModule {}
|
||||
`
|
||||
|
@ -1554,8 +1554,8 @@ describe('compiler compliance: styling', () => {
|
|||
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$.ɵɵstylePropInterpolate1("background", "url(", ctx.myUrl1, ")");
|
||||
$r3$.ɵɵstylePropInterpolate2("border-image", "url(", ctx.myUrl2, ") ", ctx.myRepeat, " auto");
|
||||
$r3$.ɵɵstylePropInterpolate3("box-shadow", "", ctx.myBoxX, " ", ctx.myBoxY, " ", ctx.myBoxWidth, " black");
|
||||
}
|
||||
…
|
||||
|
@ -2036,110 +2036,6 @@ describe('compiler compliance: styling', () => {
|
|||
});
|
||||
|
||||
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', () => {
|
||||
const files = {
|
||||
app: {
|
||||
|
|
|
@ -315,8 +315,6 @@ export class Identifiers {
|
|||
// sanitization-related functions
|
||||
static sanitizeHtml: o.ExternalReference = {name: 'ɵɵsanitizeHtml', moduleName: CORE};
|
||||
static sanitizeStyle: o.ExternalReference = {name: 'ɵɵsanitizeStyle', moduleName: CORE};
|
||||
static defaultStyleSanitizer:
|
||||
o.ExternalReference = {name: 'ɵɵdefaultStyleSanitizer', moduleName: CORE};
|
||||
static sanitizeResourceUrl:
|
||||
o.ExternalReference = {name: 'ɵɵsanitizeResourceUrl', 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
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {ConstantPool} from '../../constant_pool';
|
||||
import {AttributeMarker} from '../../core';
|
||||
import {AST, ASTWithSource, BindingPipe, BindingType, Interpolation} from '../../expression_parser/ast';
|
||||
import * as o from '../../output/output_ast';
|
||||
|
@ -92,9 +91,8 @@ export interface StylingInstructionCall {
|
|||
interface BoundStylingEntry {
|
||||
hasOverrideFlag: boolean;
|
||||
name: string|null;
|
||||
unit: string|null;
|
||||
suffix: string|null;
|
||||
sourceSpan: ParseSourceSpan;
|
||||
sanitize: boolean;
|
||||
value: AST;
|
||||
}
|
||||
|
||||
|
@ -217,20 +215,15 @@ export class StylingBuilder {
|
|||
|
||||
registerStyleInput(
|
||||
name: string, isMapBased: boolean, value: AST, sourceSpan: ParseSourceSpan,
|
||||
unit?: string|null): BoundStylingEntry|null {
|
||||
suffix?: string|null): BoundStylingEntry|null {
|
||||
if (isEmptyExpression(value)) {
|
||||
return null;
|
||||
}
|
||||
name = normalizePropName(name);
|
||||
const {property, hasOverrideFlag, unit: bindingUnit} = parseProperty(name);
|
||||
const entry: BoundStylingEntry = {
|
||||
name: property,
|
||||
sanitize: property ? isStyleSanitizable(property) : true,
|
||||
unit: unit || bindingUnit,
|
||||
value,
|
||||
sourceSpan,
|
||||
hasOverrideFlag
|
||||
};
|
||||
const {property, hasOverrideFlag, suffix: bindingSuffix} = parseProperty(name);
|
||||
suffix = typeof suffix === 'string' && suffix.length !== 0 ? suffix : bindingSuffix;
|
||||
const entry:
|
||||
BoundStylingEntry = {name: property, suffix: suffix, value, sourceSpan, hasOverrideFlag};
|
||||
if (isMapBased) {
|
||||
this._styleMapInput = entry;
|
||||
} else {
|
||||
|
@ -250,8 +243,8 @@ export class StylingBuilder {
|
|||
return null;
|
||||
}
|
||||
const {property, hasOverrideFlag} = parseProperty(name);
|
||||
const entry: BoundStylingEntry =
|
||||
{name: property, value, sourceSpan, sanitize: false, hasOverrideFlag, unit: null};
|
||||
const entry:
|
||||
BoundStylingEntry = {name: property, value, sourceSpan, hasOverrideFlag, suffix: null};
|
||||
if (isMapBased) {
|
||||
if (this._classMapInput) {
|
||||
throw new Error(
|
||||
|
@ -430,7 +423,7 @@ export class StylingBuilder {
|
|||
allocateBindingSlots: totalBindingSlotsRequired,
|
||||
supportsInterpolation: !!getInterpolationExpressionFn,
|
||||
params: (convertFn: (value: any) => o.Expression | o.Expression[]) => {
|
||||
// params => stylingProp(propName, value, suffix|sanitizer)
|
||||
// params => stylingProp(propName, value, suffix)
|
||||
const params: o.Expression[] = [];
|
||||
params.push(o.literal(input.name));
|
||||
|
||||
|
@ -441,16 +434,10 @@ export class StylingBuilder {
|
|||
params.push(convertResult);
|
||||
}
|
||||
|
||||
// [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));
|
||||
}
|
||||
// [style.prop] bindings may use suffix values (e.g. px, em, etc...), therefore,
|
||||
// if that is detected then we need to pass that in as an optional param.
|
||||
if (!isClassBased && input.suffix !== null) {
|
||||
params.push(o.literal(input.suffix));
|
||||
}
|
||||
|
||||
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):
|
||||
{property: string, unit: string, hasOverrideFlag: boolean} {
|
||||
{property: string, suffix: string|null, hasOverrideFlag: boolean} {
|
||||
let hasOverrideFlag = false;
|
||||
const overrideIndex = name.indexOf(IMPORTANT_FLAG);
|
||||
if (overrideIndex !== -1) {
|
||||
|
@ -545,15 +513,15 @@ export function parseProperty(name: string):
|
|||
hasOverrideFlag = true;
|
||||
}
|
||||
|
||||
let unit = '';
|
||||
let suffix: string|null = null;
|
||||
let property = name;
|
||||
const unitIndex = name.lastIndexOf('.');
|
||||
if (unitIndex > 0) {
|
||||
unit = name.substr(unitIndex + 1);
|
||||
suffix = name.substr(unitIndex + 1);
|
||||
property = name.substring(0, unitIndex);
|
||||
}
|
||||
|
||||
return {property, unit, hasOverrideFlag};
|
||||
return {property, suffix, hasOverrideFlag};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -227,7 +227,6 @@ export {
|
|||
ɵɵstylePropInterpolate7,
|
||||
ɵɵstylePropInterpolate8,
|
||||
ɵɵstylePropInterpolateV,
|
||||
ɵɵstyleSanitizer,
|
||||
ɵɵtemplate,
|
||||
ɵɵtemplateRefExtractor,
|
||||
ɵɵtext,
|
||||
|
@ -286,7 +285,6 @@ export {
|
|||
bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl,
|
||||
} from './sanitization/bypass';
|
||||
export {
|
||||
ɵɵdefaultStyleSanitizer,
|
||||
ɵɵsanitizeHtml,
|
||||
ɵɵsanitizeResourceUrl,
|
||||
ɵɵsanitizeScript,
|
||||
|
|
|
@ -113,7 +113,6 @@ export {
|
|||
ɵɵstylePropInterpolate8,
|
||||
ɵɵstylePropInterpolateV,
|
||||
|
||||
ɵɵstyleSanitizer,
|
||||
ɵɵtemplate,
|
||||
|
||||
ɵɵtext,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
import {bindingUpdated} from '../bindings';
|
||||
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';
|
||||
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*/
|
||||
|
||||
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 {assertDefined, assertEqual, assertLessThan, assertNotEqual, throwError} from '../../util/assert';
|
||||
import {EMPTY_ARRAY} from '../../util/empty';
|
||||
|
@ -18,11 +16,10 @@ import {bindingUpdated} from '../bindings';
|
|||
import {DirectiveDef} from '../interfaces/definition';
|
||||
import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||
import {RElement, Renderer3} from '../interfaces/renderer';
|
||||
import {SanitizerFn} from '../interfaces/sanitization';
|
||||
import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling';
|
||||
import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view';
|
||||
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 {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser';
|
||||
import {NO_CHANGE} from '../tokens';
|
||||
|
@ -31,26 +28,6 @@ import {getNativeByIndex} from '../util/view_utils';
|
|||
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.
|
||||
*
|
||||
|
@ -64,8 +41,6 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn|null): void {
|
|||
* @param prop A valid CSS property.
|
||||
* @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`.
|
||||
* 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
|
||||
* within a host binding function.
|
||||
|
@ -183,11 +158,11 @@ export function classStringParser(keyValueArray: KeyValueArray<any>, text: strin
|
|||
*
|
||||
* @param prop property name.
|
||||
* @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`)
|
||||
*/
|
||||
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 {
|
||||
const lView = getLView();
|
||||
const tView = getTView();
|
||||
|
@ -199,19 +174,10 @@ export function checkStylingProperty(
|
|||
stylingFirstUpdatePass(tView, prop, bindingIndex, isClassBased);
|
||||
}
|
||||
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;
|
||||
updateStyling(
|
||||
tView, tNode, lView, lView[RENDERER], prop,
|
||||
lView[bindingIndex + 1] = normalizeAndApplySuffixOrSanitizer(value, suffixOrSanitizer),
|
||||
isClassBased, bindingIndex);
|
||||
lView[bindingIndex + 1] = normalizeSuffix(value, suffix), isClassBased, bindingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,9 +185,7 @@ export function checkStylingProperty(
|
|||
* Common code between `ɵɵclassMap` and `ɵɵstyleMap`.
|
||||
*
|
||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||
* function so that
|
||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
||||
* purposes.
|
||||
* function so that `style` can be processed. This is done for tree shaking purposes.
|
||||
* @param stringParser Parser used to parse `value` if `string`. (Passed in as `style` and `class`
|
||||
* have different parsers.)
|
||||
* @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.
|
||||
*
|
||||
* @param keyValueArraySet (See `keyValueArraySet` in "util/array_utils") Gets passed in as a
|
||||
* function so that
|
||||
* `style` can pass in version which does sanitization. This is done for tree shaking
|
||||
* purposes.
|
||||
* function so that `style` can be processed. This is done
|
||||
* for tree shaking purposes.
|
||||
* @param stringParser The parser is passed in so that it will be tree shakable. See
|
||||
* `styleStringParser` and `classStringParser`
|
||||
* @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
|
||||
*
|
||||
* @param keyValueArray KeyValueArray to add to.
|
||||
* @param key Style key to add. (This key will be checked if it needs sanitization)
|
||||
* @param value The value to set (If key needs sanitization it will be sanitized)
|
||||
* @param key Style key to add.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
export function styleKeyValueArraySet(keyValueArray: KeyValueArray<any>, key: string, value: any) {
|
||||
if (stylePropNeedsSanitization(key)) {
|
||||
value = ɵɵsanitizeStyle(value);
|
||||
}
|
||||
keyValueArraySet(keyValueArray, key, value);
|
||||
keyValueArraySet(keyValueArray, key, unwrapSafeValue(value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -784,10 +744,7 @@ function updateStyling(
|
|||
* NOTE: The styling stores two values.
|
||||
* 1. The raw value which came from the application is stored at `index + 0` location. (This value
|
||||
* is used for dirty checking).
|
||||
* 2. The normalized value (converted to `KeyValueArray` if map and sanitized) is stored at `index +
|
||||
* 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.
|
||||
* 2. The normalized value is stored at `index + 1`.
|
||||
*
|
||||
* @param tData `TData` used for traversing the priority.
|
||||
* @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
|
||||
* @param value
|
||||
* @param suffixOrSanitizer
|
||||
* @param suffix
|
||||
*/
|
||||
function normalizeAndApplySuffixOrSanitizer(
|
||||
value: any, suffixOrSanitizer: SanitizerFn|string|undefined|null): string|null|undefined|
|
||||
boolean {
|
||||
function normalizeSuffix(value: any, suffix: string|undefined|null): string|null|undefined|boolean {
|
||||
if (value == null /** || value === undefined */) {
|
||||
// do nothing
|
||||
} else if (typeof suffixOrSanitizer === 'function') {
|
||||
// sanitize the value.
|
||||
value = suffixOrSanitizer(value);
|
||||
} else if (typeof suffixOrSanitizer === 'string') {
|
||||
value = value + suffixOrSanitizer;
|
||||
} else if (typeof suffix === 'string') {
|
||||
value = value + suffix;
|
||||
} else if (typeof value === 'object') {
|
||||
value = stringify(unwrapSafeValue(value));
|
||||
}
|
||||
|
|
|
@ -133,7 +133,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,
|
||||
|
@ -164,7 +163,6 @@ export const angularCoreEnv: {[name: string]: Function} =
|
|||
|
||||
'ɵɵsanitizeHtml': sanitization.ɵɵsanitizeHtml,
|
||||
'ɵɵsanitizeStyle': sanitization.ɵɵsanitizeStyle,
|
||||
'ɵɵdefaultStyleSanitizer': sanitization.ɵɵdefaultStyleSanitizer,
|
||||
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
||||
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
||||
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||
import {assertDefined, assertEqual} from '../util/assert';
|
||||
import {assertLViewOrUndefined} from './assert';
|
||||
import {DirectiveDef} from './interfaces/definition';
|
||||
|
@ -97,11 +96,6 @@ interface LFrame {
|
|||
*/
|
||||
currentNamespace: string|null;
|
||||
|
||||
/**
|
||||
* Current sanitizer
|
||||
*/
|
||||
currentSanitizer: StyleSanitizeFn|null;
|
||||
|
||||
|
||||
/**
|
||||
* 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.currentDirectiveIndex, -1, '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.currentQueryIndex, 0, 'Expected clean LFrame');
|
||||
}
|
||||
|
@ -454,7 +447,6 @@ function createLFrame(parent: LFrame|null): LFrame {
|
|||
contextLView: null!, //
|
||||
elementDepthCount: 0, //
|
||||
currentNamespace: null, //
|
||||
currentSanitizer: null, //
|
||||
currentDirectiveIndex: -1, //
|
||||
bindingRootIndex: -1, //
|
||||
bindingIndex: -1, //
|
||||
|
@ -508,7 +500,6 @@ export function leaveView() {
|
|||
oldLFrame.elementDepthCount = 0;
|
||||
oldLFrame.currentDirectiveIndex = -1;
|
||||
oldLFrame.currentNamespace = null;
|
||||
oldLFrame.currentSanitizer = null;
|
||||
oldLFrame.bindingRootIndex = -1;
|
||||
oldLFrame.bindingIndex = -1;
|
||||
oldLFrame.currentQueryIndex = 0;
|
||||
|
@ -602,18 +593,3 @@ export function namespaceHTMLInternal() {
|
|||
export function getNamespace(): string|null {
|
||||
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 {Sanitizer} from './sanitizer';
|
||||
import {SecurityContext} from './security';
|
||||
import {StyleSanitizeFn, StyleSanitizeMode} from './style_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (name.toLowerCase().startsWith('on')) {
|
||||
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')
|
||||
.it('should sanitize style values before writing them', () => {
|
||||
.it('should not sanitize style values before writing them', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div [style.width]="widthExp"
|
||||
|
@ -1914,7 +1914,7 @@ describe('styling', () => {
|
|||
});
|
||||
|
||||
onlyInIvy('only ivy has [style] support')
|
||||
.it('should sanitize style values before writing them', () => {
|
||||
.it('should not sanitize style values before writing them', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div [style.width]="widthExp"
|
||||
|
|
|
@ -596,9 +596,6 @@
|
|||
{
|
||||
"name": "getCurrentDirectiveIndex"
|
||||
},
|
||||
{
|
||||
"name": "getCurrentStyleSanitizer"
|
||||
},
|
||||
{
|
||||
"name": "getDebugContext"
|
||||
},
|
||||
|
@ -1017,7 +1014,7 @@
|
|||
"name": "noSideEffects"
|
||||
},
|
||||
{
|
||||
"name": "normalizeAndApplySuffixOrSanitizer"
|
||||
"name": "normalizeSuffix"
|
||||
},
|
||||
{
|
||||
"name": "readPatchedData"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import {DirectiveDef} from '@angular/core/src/render3';
|
||||
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 {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';
|
||||
|
|
|
@ -10,10 +10,10 @@ import {NgForOfContext} from '@angular/common';
|
|||
import {getSortedClassName} from '@angular/core/testing/src/styling';
|
||||
|
||||
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, 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 {SecurityContext} from '../../src/sanitization/security';
|
||||
|
||||
|
@ -170,7 +170,6 @@ describe('instructions', () => {
|
|||
return createDiv();
|
||||
},
|
||||
() => {
|
||||
ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer);
|
||||
ɵɵstyleProp('background-image', backgroundImage);
|
||||
},
|
||||
2, 2);
|
||||
|
@ -199,35 +198,6 @@ describe('instructions', () => {
|
|||
fixture.update();
|
||||
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', () => {
|
||||
|
@ -559,9 +529,6 @@ class LocalMockSanitizer implements Sanitizer {
|
|||
class MockSanitizerInterceptor {
|
||||
public lastValue: string|null = null;
|
||||
constructor(private _interceptorFn?: ((value: any) => any)|null) {}
|
||||
getStyleSanitizer() {
|
||||
return ɵɵdefaultStyleSanitizer;
|
||||
}
|
||||
sanitize(context: SecurityContext, value: LocalSanitizedValue|string|null|any): string|null {
|
||||
if (this._interceptorFn) {
|
||||
this._interceptorFn(value);
|
||||
|
|
Loading…
Reference in New Issue