revert: refactor(ivy): remove styleSanitizer instruction in favor of an inline param (#34480) (#34910)

This reverts commit 84d24c08e1.

PR Close #34910
This commit is contained in:
Matias Niemelä
2020-01-22 12:33:06 -08:00
parent d8c29ffb28
commit d4c1ab54a0
11 changed files with 135 additions and 128 deletions

View File

@ -122,6 +122,7 @@ export {
ɵɵelementContainerEnd,
ɵɵelementContainer,
ɵɵstyleMap,
ɵɵstyleSanitizer,
ɵɵclassMap,
ɵɵclassMapInterpolate1,
ɵɵclassMapInterpolate2,

View File

@ -115,6 +115,7 @@ export {
ɵɵstylePropInterpolate8,
ɵɵstylePropInterpolateV,
ɵɵstyleSanitizer,
ɵɵtemplate,
ɵɵtext,

View File

@ -6,7 +6,6 @@
* 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';
@ -16,7 +15,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, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
import {applyStylingMapDirectly, applyStylingValueDirectly, flushStyling, setClass, setStyle, updateClassViaContext, updateStyleViaContext} from '../styling/bindings';
import {activateStylingMapFeature} from '../styling/map_based_bindings';
import {attachStylingDebugObject} from '../styling/styling_debug';
import {NO_CHANGE} from '../tokens';
@ -36,6 +35,26 @@ 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.
*
@ -59,8 +78,8 @@ import {getNativeByTNode, getTNode} from '../util/view_utils';
*/
export function ɵɵstyleProp(
prop: string, value: string | number | SafeValue | null,
suffixOrSanitizer?: StyleSanitizeFn | string | null): typeof ɵɵstyleProp {
stylePropInternal(getSelectedIndex(), prop, value, suffixOrSanitizer);
suffix?: string | null): typeof ɵɵstyleProp {
stylePropInternal(getSelectedIndex(), prop, value, suffix);
return ɵɵstyleProp;
}
@ -72,7 +91,7 @@ export function ɵɵstyleProp(
*/
export function stylePropInternal(
elementIndex: number, prop: string, value: string | number | SafeValue | null,
suffixOrSanitizer?: StyleSanitizeFn | string | null): void {
suffix?: string | null | undefined): 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
@ -90,12 +109,9 @@ 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, sanitizer);
false);
if (ngDevMode) {
ngDevMode.styleProp++;
if (updated) {
@ -138,8 +154,7 @@ export function ɵɵclassProp(className: string, value: boolean | null): typeof
patchHostStylingFlag(tNode, isHostStyling(), true);
}
const updated =
stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true, null);
const updated = stylingProp(tNode, firstUpdatePass, lView, bindingIndex, className, value, true);
if (ngDevMode) {
ngDevMode.classProp++;
if (updated) {
@ -162,15 +177,12 @@ 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, sanitizer: StyleSanitizeFn | null | undefined): boolean {
isClassBased: boolean): 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.
@ -271,8 +283,7 @@ export function ɵɵstyleMap(styles: {[styleName: string]: any} | NO_CHANGE | nu
}
stylingMap(
context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput,
ɵɵdefaultStyleSanitizer);
context, tNode, firstUpdatePass, lView, bindingIndex, styles, false, hasDirectiveInput);
}
/**
@ -335,7 +346,7 @@ export function classMapInternal(
}
stylingMap(
context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput, null);
context, tNode, firstUpdatePass, lView, bindingIndex, classes, true, hasDirectiveInput);
}
/**
@ -347,11 +358,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, sanitizer: StyleSanitizeFn | null): void {
hasDirectiveInput: boolean): void {
const directiveIndex = getActiveDirectiveId();
const native = getNativeByTNode(tNode, lView) as RElement;
const oldValue = getValue(lView, bindingIndex);
setCurrentStyleSanitizer(ɵɵdefaultStyleSanitizer);
const sanitizer = getCurrentStyleSanitizer();
const valueHasChanged = hasValueChanged(oldValue, value);
// [style] and [class] bindings do not use `bind()` and will therefore

View File

@ -297,14 +297,12 @@ import {LView} from './view';
*
* It is enabled in two cases:
*
* 1. One or more styleProp instructions are generated (a sanitizer is passed in to each one).
* 1. The `styleSanitizer(sanitizerFn)` instruction was called (just before any other
* styling instructions are run).
*
* 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).
* 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).
*
* 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
@ -312,6 +310,18 @@ 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<number|string|number|boolean|null|StylingMapArray|{}> {

View File

@ -129,6 +129,7 @@ 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,

View File

@ -97,8 +97,7 @@ 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 | undefined, forceUpdate: boolean,
firstUpdatePass: boolean): boolean {
sanitizer: StyleSanitizeFn | null, forceUpdate: boolean, firstUpdatePass: boolean): boolean {
const isMapBased = !prop;
const state = getStylingState(element, directiveIndex);
const countIndex = isMapBased ? STYLING_INDEX_FOR_MAP_BINDING : state.stylesIndex++;

View File

@ -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, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index';
import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer, ɵɵ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,22 +137,20 @@ describe('instructions', () => {
describe('styleProp', () => {
it('should automatically sanitize unless a bypass operation is applied', () => {
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('');
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('<div></div>');
t.update(() => {
ɵɵstyleProp(
'background-image', bypassSanitizationTrustStyle('url("http://server2")'),
ɵɵdefaultStyleSanitizer);
ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer);
ɵɵstyleProp('background-image', bypassSanitizationTrustStyle('url("http://server2")'));
});
expect(element.style.getPropertyValue('background-image')).toEqual('url("http://server2")');
expect((t.hostElement.firstChild as HTMLElement).style.getPropertyValue('background-image'))
.toEqual('url("http://server2")');
});
});
@ -162,14 +160,10 @@ describe('instructions', () => {
function createDivWithStyle() { ɵɵelement(0, 'div', 0); }
it('should add style', () => {
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');
const fixture = new TemplateFixture(
createDivWithStyle, () => {}, 1, 0, null, null, null, undefined, attrs);
fixture.update(() => { ɵɵstyleMap({'background-color': 'red'}); });
expect(fixture.html).toEqual('<div style="background-color: red; height: 10px;"></div>');
});
it('should sanitize new styles that may contain `url` properties', () => {
@ -179,6 +173,7 @@ describe('instructions', () => {
const fixture = new TemplateFixture(
() => { return createDiv(); }, //
() => {
ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer());
ɵɵstyleMap({
'background-image': 'background-image',
'background': 'background',