Revert "feat(ivy): added namespaced attributes (#23899)"
This reverts commit d6989c80d3
.
This commit is contained in:
parent
3128b26e5c
commit
07b4c8be42
|
@ -260,11 +260,8 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
|
||||||
const attrs = tElement.attrs;
|
const attrs = tElement.attrs;
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
for (let i = 0; i < attrs.length; i = i + 2) {
|
for (let i = 0; i < attrs.length; i = i + 2) {
|
||||||
let attrName = attrs[i];
|
const attrName = attrs[i];
|
||||||
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
||||||
if (attrName === 0) { // NS.FULL
|
|
||||||
attrName = attrs[i += 2];
|
|
||||||
}
|
|
||||||
if (attrName == attrNameToInject) {
|
if (attrName == attrNameToInject) {
|
||||||
return attrs[i + 1] as string;
|
return attrs[i + 1] as string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -842,19 +842,7 @@ export function createTView(
|
||||||
function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
||||||
const isProc = isProceduralRenderer(renderer);
|
const isProc = isProceduralRenderer(renderer);
|
||||||
for (let i = 0; i < attrs.length; i += 2) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
let attrName = attrs[i];
|
const attrName = attrs[i];
|
||||||
if (attrName === 0) { // NS.FULL
|
|
||||||
// Namespaced attribute
|
|
||||||
const attrNS = attrs[i + 1] as string;
|
|
||||||
attrName = attrs[i + 2] as string;
|
|
||||||
const attrVal = attrs[i + 3] as string;
|
|
||||||
i += 2;
|
|
||||||
if (isProc) {
|
|
||||||
(renderer as ProceduralRenderer3).setAttribute(native, attrName, attrVal, attrNS);
|
|
||||||
} else {
|
|
||||||
native.setAttributeNS(attrNS, attrName, attrVal);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
if (attrName === AttributeMarker.SELECT_ONLY) break;
|
||||||
if (attrName !== NG_PROJECT_AS_ATTR_NAME) {
|
if (attrName !== NG_PROJECT_AS_ATTR_NAME) {
|
||||||
const attrVal = attrs[i + 1];
|
const attrVal = attrs[i + 1];
|
||||||
|
@ -866,7 +854,6 @@ function setUpAttributes(native: RElement, attrs: TAttributes): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export function createError(text: string, token: any) {
|
export function createError(text: string, token: any) {
|
||||||
return new Error(`Renderer: ${text} [${stringify(token)}]`);
|
return new Error(`Renderer: ${text} [${stringify(token)}]`);
|
||||||
|
@ -1506,8 +1493,7 @@ function generateInitialInputs(
|
||||||
|
|
||||||
const attrs = tNode.attrs !;
|
const attrs = tNode.attrs !;
|
||||||
for (let i = 0; i < attrs.length; i += 2) {
|
for (let i = 0; i < attrs.length; i += 2) {
|
||||||
const first = attrs[i];
|
const attrName = attrs[i];
|
||||||
const attrName = first === 0 ? attrs[i += 2] : first; // 0 = NS.FULL
|
|
||||||
const minifiedInputName = inputs[attrName];
|
const minifiedInputName = inputs[attrName];
|
||||||
const attrValue = attrs[i + 1];
|
const attrValue = attrs[i + 1];
|
||||||
|
|
||||||
|
@ -1920,7 +1906,7 @@ function appendToProjectionNode(
|
||||||
* - 1 based index of the selector from the {@link projectionDef}
|
* - 1 based index of the selector from the {@link projectionDef}
|
||||||
*/
|
*/
|
||||||
export function projection(
|
export function projection(
|
||||||
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: TAttributes): void {
|
nodeIndex: number, localIndex: number, selectorIndex: number = 0, attrs?: string[]): void {
|
||||||
const node = createLNode(
|
const node = createLNode(
|
||||||
nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null});
|
nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null});
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LContainer} from './container';
|
import {LContainer} from './container';
|
||||||
import {LInjector} from './injector';
|
import {LInjector} from './injector';
|
||||||
import {LProjection} from './projection';
|
import {LProjection} from './projection';
|
||||||
|
@ -13,16 +14,6 @@ import {RElement, RNode, RText} from './renderer';
|
||||||
import {LView, TData, TView} from './view';
|
import {LView, TData, TView} from './view';
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespace attribute flags.
|
|
||||||
*/
|
|
||||||
export const enum NS {
|
|
||||||
/**
|
|
||||||
* Use the next value as the full namespaces URI, the values after that
|
|
||||||
* are then the name and the value, respectively.
|
|
||||||
*/
|
|
||||||
FULL = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TNodeType corresponds to the TNode.type property. It contains information
|
* TNodeType corresponds to the TNode.type property. It contains information
|
||||||
|
@ -188,7 +179,7 @@ export const enum AttributeMarker {
|
||||||
* - attribute names and values
|
* - attribute names and values
|
||||||
* - special markers acting as flags to alter attributes processing.
|
* - special markers acting as flags to alter attributes processing.
|
||||||
*/
|
*/
|
||||||
export type TAttributes = (string | AttributeMarker | NS)[];
|
export type TAttributes = (string | AttributeMarker)[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LNode binding data (flyweight) for a particular node that is shared between all templates
|
* LNode binding data (flyweight) for a particular node that is shared between all templates
|
||||||
|
|
|
@ -106,12 +106,8 @@ function findAttrIndexInNode(name: string, attrs: TAttributes | null): number {
|
||||||
if (attrs === null) return -1;
|
if (attrs === null) return -1;
|
||||||
for (let i = 0; i < attrs.length; i += step) {
|
for (let i = 0; i < attrs.length; i += step) {
|
||||||
const attrName = attrs[i];
|
const attrName = attrs[i];
|
||||||
if (attrName === 0) {
|
if (attrName === name) return i;
|
||||||
// NS.FULL
|
if (attrName === AttributeMarker.SELECT_ONLY) {
|
||||||
step = 2;
|
|
||||||
} else if (attrName === name) {
|
|
||||||
return i;
|
|
||||||
} else if (attrName === AttributeMarker.SELECT_ONLY) {
|
|
||||||
step = 1;
|
step = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {NgForOfContext} from '@angular/common';
|
||||||
import {RenderFlags, directiveInject} from '../../src/render3';
|
import {RenderFlags, directiveInject} from '../../src/render3';
|
||||||
import {defineComponent} from '../../src/render3/definition';
|
import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bind, container, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleNamed, interpolation1, renderTemplate, setHtmlNS, setSvgNS, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, elementAttribute, elementClass, elementEnd, elementProperty, elementStart, elementStyle, elementStyleNamed, interpolation1, renderTemplate, setHtmlNS, setSvgNS, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {LElementNode, LNode, NS} from '../../src/render3/interfaces/node';
|
import {LElementNode, LNode} from '../../src/render3/interfaces/node';
|
||||||
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
import {RElement, domRendererFactory3} from '../../src/render3/interfaces/renderer';
|
||||||
import {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
|
import {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization';
|
||||||
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
|
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
|
||||||
|
@ -91,43 +91,6 @@ describe('instructions', () => {
|
||||||
rendererSetAttribute: 2
|
rendererSetAttribute: 2
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use sanitizer function even on elements with namespaced attributes', () => {
|
|
||||||
const t = new TemplateFixture(() => {
|
|
||||||
elementStart(0, 'div', [
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.example.com/2004/test',
|
|
||||||
'whatever',
|
|
||||||
'abc',
|
|
||||||
]);
|
|
||||||
elementEnd();
|
|
||||||
});
|
|
||||||
|
|
||||||
t.update(() => elementAttribute(0, 'title', 'javascript:true', sanitizeUrl));
|
|
||||||
|
|
||||||
|
|
||||||
let standardHTML = '<div whatever="abc" title="unsafe:javascript:true"></div>';
|
|
||||||
let ieHTML = '<div title="unsafe:javascript:true" whatever="abc"></div>';
|
|
||||||
|
|
||||||
expect([standardHTML, ieHTML]).toContain(t.html);
|
|
||||||
|
|
||||||
t.update(
|
|
||||||
() => elementAttribute(
|
|
||||||
0, 'title', bypassSanitizationTrustUrl('javascript:true'), sanitizeUrl));
|
|
||||||
|
|
||||||
standardHTML = '<div whatever="abc" title="javascript:true"></div>';
|
|
||||||
ieHTML = '<div title="javascript:true" whatever="abc"></div>';
|
|
||||||
|
|
||||||
expect([standardHTML, ieHTML]).toContain(t.html);
|
|
||||||
|
|
||||||
expect(ngDevMode).toHaveProperties({
|
|
||||||
firstTemplatePass: 1,
|
|
||||||
tNode: 2,
|
|
||||||
tView: 1,
|
|
||||||
rendererCreateElement: 1,
|
|
||||||
rendererSetAttribute: 2
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('elementProperty', () => {
|
describe('elementProperty', () => {
|
||||||
|
@ -445,11 +408,6 @@ describe('instructions', () => {
|
||||||
// height="300"
|
// height="300"
|
||||||
'height',
|
'height',
|
||||||
'300',
|
'300',
|
||||||
// test:title="abc"
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.example.com/2014/test',
|
|
||||||
'title',
|
|
||||||
'abc',
|
|
||||||
]);
|
]);
|
||||||
elementStart(2, 'circle', ['cx', '200', 'cy', '150', 'fill', '#0000ff']);
|
elementStart(2, 'circle', ['cx', '200', 'cy', '150', 'fill', '#0000ff']);
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
@ -461,71 +419,12 @@ describe('instructions', () => {
|
||||||
|
|
||||||
// Most browsers will print <circle></circle>, some will print <circle />, both are valid
|
// Most browsers will print <circle></circle>, some will print <circle />, both are valid
|
||||||
const standardHTML =
|
const standardHTML =
|
||||||
'<div id="container"><svg id="display" width="400" height="300" title="abc"><circle cx="200" cy="150" fill="#0000ff"></circle></svg></div>';
|
'<div id="container"><svg id="display" width="400" height="300"><circle cx="200" cy="150" fill="#0000ff"></circle></svg></div>';
|
||||||
const ie11HTML =
|
const ie11HTML =
|
||||||
'<div id="container"><svg xmlns="http://www.w3.org/2000/svg" xmlns:NS1="http://www.example.com/2014/test" NS1:title="abc" id="display" width="400" height="300"><circle fill="#0000ff" cx="200" cy="150" /></svg></div>';
|
'<div id="container"><svg xmlns="http://www.w3.org/2000/svg" id="display" width="400" height="300"><circle fill="#0000ff" cx="200" cy="150" /></svg></div>';
|
||||||
|
|
||||||
expect([standardHTML, ie11HTML]).toContain(t.html);
|
expect([standardHTML, ie11HTML]).toContain(t.html);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set an attribute with a namespace', () => {
|
|
||||||
const t = new TemplateFixture(() => {
|
|
||||||
elementStart(0, 'div', [
|
|
||||||
'id',
|
|
||||||
'container',
|
|
||||||
// test:title="abc"
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.example.com/2014/test',
|
|
||||||
'title',
|
|
||||||
'abc',
|
|
||||||
]);
|
|
||||||
elementEnd();
|
|
||||||
});
|
|
||||||
|
|
||||||
const standardHTML = '<div id="container" title="abc"></div>';
|
|
||||||
const ie11HTML =
|
|
||||||
'<div id="container" xmlns:NS1="https://www.example.com/2014/test" NS1:title="abc"></div>';
|
|
||||||
expect([standardHTML, ie11HTML]).toContain(t.html);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set attributes including more than one namespaced attribute', () => {
|
|
||||||
const t = new TemplateFixture(() => {
|
|
||||||
elementStart(0, 'div', [
|
|
||||||
'id',
|
|
||||||
'container',
|
|
||||||
|
|
||||||
// NS1:title="abc"
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.example.com/2014/test',
|
|
||||||
'title',
|
|
||||||
'abc',
|
|
||||||
|
|
||||||
// style="background: #dead11"
|
|
||||||
'style',
|
|
||||||
'background: #dead11',
|
|
||||||
|
|
||||||
// NS1:whatever="wee"
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.example.com/2014/test',
|
|
||||||
'whatever',
|
|
||||||
'wee',
|
|
||||||
|
|
||||||
// NS2:shazbot="wocka wocka"
|
|
||||||
NS.FULL,
|
|
||||||
'http://www.whatever.com/2016/blah',
|
|
||||||
'shazbot',
|
|
||||||
'wocka wocka',
|
|
||||||
]);
|
|
||||||
elementEnd();
|
|
||||||
});
|
|
||||||
|
|
||||||
const standardHTML =
|
|
||||||
'<div id="container" title="abc" style="background: #dead11" whatever="wee" shazbot="wocka wocka"></div>';
|
|
||||||
const ieHTML =
|
|
||||||
'<div id="container" style="background: rgb(222, 173, 17);" title="abc" whatever="wee" shazbot="wocka wocka"></div>';
|
|
||||||
|
|
||||||
expect([standardHTML, ieHTML]).toContain(t.html);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,14 +28,23 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer';
|
||||||
|
|
||||||
describe('setAttribute', () => {
|
describe('setAttribute', () => {
|
||||||
describe('with namespace', () => {
|
describe('with namespace', () => {
|
||||||
|
it('xmlns', () => shouldSetAttributeWithNs('xmlns'));
|
||||||
it('xml', () => shouldSetAttributeWithNs('xml'));
|
it('xml', () => shouldSetAttributeWithNs('xml'));
|
||||||
it('svg', () => shouldSetAttributeWithNs('svg'));
|
it('svg', () => shouldSetAttributeWithNs('svg'));
|
||||||
it('xhtml', () => shouldSetAttributeWithNs('xhtml'));
|
it('xhtml', () => shouldSetAttributeWithNs('xhtml'));
|
||||||
it('xlink', () => shouldSetAttributeWithNs('xlink'));
|
it('xlink', () => shouldSetAttributeWithNs('xlink'));
|
||||||
it('custom', () => shouldSetAttributeWithNs('custom'));
|
|
||||||
|
it('unknown', () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
expect(div.hasAttribute('unknown:name')).toBe(false);
|
||||||
|
|
||||||
|
renderer.setAttribute(div, 'name', 'value', 'unknown');
|
||||||
|
|
||||||
|
expect(div.getAttribute('unknown:name')).toBe('value');
|
||||||
|
});
|
||||||
|
|
||||||
function shouldSetAttributeWithNs(namespace: string): void {
|
function shouldSetAttributeWithNs(namespace: string): void {
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
const namespaceUri = NAMESPACE_URIS[namespace];
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(false);
|
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(false);
|
||||||
|
|
||||||
|
@ -48,16 +57,26 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer';
|
||||||
|
|
||||||
describe('removeAttribute', () => {
|
describe('removeAttribute', () => {
|
||||||
describe('with namespace', () => {
|
describe('with namespace', () => {
|
||||||
|
it('xmlns', () => shouldRemoveAttributeWithNs('xmlns'));
|
||||||
it('xml', () => shouldRemoveAttributeWithNs('xml'));
|
it('xml', () => shouldRemoveAttributeWithNs('xml'));
|
||||||
it('svg', () => shouldRemoveAttributeWithNs('svg'));
|
it('svg', () => shouldRemoveAttributeWithNs('svg'));
|
||||||
it('xhtml', () => shouldRemoveAttributeWithNs('xhtml'));
|
it('xhtml', () => shouldRemoveAttributeWithNs('xhtml'));
|
||||||
it('xlink', () => shouldRemoveAttributeWithNs('xlink'));
|
it('xlink', () => shouldRemoveAttributeWithNs('xlink'));
|
||||||
it('custom', () => shouldRemoveAttributeWithNs('custom'));
|
|
||||||
|
it('unknown', () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.setAttribute('unknown:name', 'value');
|
||||||
|
expect(div.hasAttribute('unknown:name')).toBe(true);
|
||||||
|
|
||||||
|
renderer.removeAttribute(div, 'name', 'unknown');
|
||||||
|
|
||||||
|
expect(div.hasAttribute('unknown:name')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
function shouldRemoveAttributeWithNs(namespace: string): void {
|
function shouldRemoveAttributeWithNs(namespace: string): void {
|
||||||
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
const namespaceUri = NAMESPACE_URIS[namespace];
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.setAttributeNS(namespaceUri, 'name', 'value');
|
div.setAttributeNS(namespaceUri, `${namespace}:name`, 'value');
|
||||||
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(true);
|
expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(true);
|
||||||
|
|
||||||
renderer.removeAttribute(div, 'name', namespace);
|
renderer.removeAttribute(div, 'name', namespace);
|
||||||
|
|
Loading…
Reference in New Issue