diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 4cc09c5b2d..1c55e79fa6 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -260,11 +260,8 @@ export function injectAttribute(attrNameToInject: string): string|undefined { const attrs = tElement.attrs; if (attrs) { 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 === 0) { // NS.FULL - attrName = attrs[i += 2]; - } if (attrName == attrNameToInject) { return attrs[i + 1] as string; } diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index ef9e7d9540..13952a0761 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -842,28 +842,15 @@ export function createTView( function setUpAttributes(native: RElement, attrs: TAttributes): void { const isProc = isProceduralRenderer(renderer); for (let i = 0; i < attrs.length; i += 2) { - let 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 !== NG_PROJECT_AS_ATTR_NAME) { - const attrVal = attrs[i + 1]; - ngDevMode && ngDevMode.rendererSetAttribute++; - isProc ? - (renderer as ProceduralRenderer3) - .setAttribute(native, attrName as string, attrVal as string) : - native.setAttribute(attrName as string, attrVal as string); - } + const attrName = attrs[i]; + if (attrName === AttributeMarker.SELECT_ONLY) break; + if (attrName !== NG_PROJECT_AS_ATTR_NAME) { + const attrVal = attrs[i + 1]; + ngDevMode && ngDevMode.rendererSetAttribute++; + isProc ? + (renderer as ProceduralRenderer3) + .setAttribute(native, attrName as string, attrVal as string) : + native.setAttribute(attrName as string, attrVal as string); } } } @@ -1506,8 +1493,7 @@ function generateInitialInputs( const attrs = tNode.attrs !; for (let i = 0; i < attrs.length; i += 2) { - const first = attrs[i]; - const attrName = first === 0 ? attrs[i += 2] : first; // 0 = NS.FULL + const attrName = attrs[i]; const minifiedInputName = inputs[attrName]; const attrValue = attrs[i + 1]; @@ -1920,7 +1906,7 @@ function appendToProjectionNode( * - 1 based index of the selector from the {@link projectionDef} */ 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( nodeIndex, TNodeType.Projection, null, null, attrs || null, {head: null, tail: null}); diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index 00ea8220a7..d4ac991ada 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -5,6 +5,7 @@ * 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 {LContainer} from './container'; import {LInjector} from './injector'; import {LProjection} from './projection'; @@ -13,16 +14,6 @@ import {RElement, RNode, RText} from './renderer'; 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 @@ -188,7 +179,7 @@ export const enum AttributeMarker { * - attribute names and values * - 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 diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index 5f6f8b5ed0..73f2ab55ec 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -106,12 +106,8 @@ function findAttrIndexInNode(name: string, attrs: TAttributes | null): number { if (attrs === null) return -1; for (let i = 0; i < attrs.length; i += step) { const attrName = attrs[i]; - if (attrName === 0) { - // NS.FULL - step = 2; - } else if (attrName === name) { - return i; - } else if (attrName === AttributeMarker.SELECT_ONLY) { + if (attrName === name) return i; + if (attrName === AttributeMarker.SELECT_ONLY) { step = 1; } } diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index 7056457990..751ab50bd8 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -11,7 +11,7 @@ import {NgForOfContext} from '@angular/common'; import {RenderFlags, directiveInject} from '../../src/render3'; 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 {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 {TrustedString, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, sanitizeHtml, sanitizeResourceUrl, sanitizeScript, sanitizeStyle, sanitizeUrl} from '../../src/sanitization/sanitization'; import {Sanitizer, SecurityContext} from '../../src/sanitization/security'; @@ -91,43 +91,6 @@ describe('instructions', () => { 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 = '
'; - let ieHTML = '
'; - - expect([standardHTML, ieHTML]).toContain(t.html); - - t.update( - () => elementAttribute( - 0, 'title', bypassSanitizationTrustUrl('javascript:true'), sanitizeUrl)); - - standardHTML = '
'; - ieHTML = '
'; - - expect([standardHTML, ieHTML]).toContain(t.html); - - expect(ngDevMode).toHaveProperties({ - firstTemplatePass: 1, - tNode: 2, - tView: 1, - rendererCreateElement: 1, - rendererSetAttribute: 2 - }); - }); }); describe('elementProperty', () => { @@ -445,11 +408,6 @@ describe('instructions', () => { // height="300" 'height', '300', - // test:title="abc" - NS.FULL, - 'http://www.example.com/2014/test', - 'title', - 'abc', ]); elementStart(2, 'circle', ['cx', '200', 'cy', '150', 'fill', '#0000ff']); elementEnd(); @@ -461,71 +419,12 @@ describe('instructions', () => { // Most browsers will print , some will print , both are valid const standardHTML = - '
'; + '
'; const ie11HTML = - '
'; + '
'; 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 = '
'; - const ie11HTML = - '
'; - 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 = - '
'; - const ieHTML = - '
'; - - expect([standardHTML, ieHTML]).toContain(t.html); - }); }); }); diff --git a/packages/platform-browser/test/dom/dom_renderer_spec.ts b/packages/platform-browser/test/dom/dom_renderer_spec.ts index d8108b97ad..1386e8b617 100644 --- a/packages/platform-browser/test/dom/dom_renderer_spec.ts +++ b/packages/platform-browser/test/dom/dom_renderer_spec.ts @@ -28,14 +28,23 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer'; describe('setAttribute', () => { describe('with namespace', () => { + it('xmlns', () => shouldSetAttributeWithNs('xmlns')); it('xml', () => shouldSetAttributeWithNs('xml')); it('svg', () => shouldSetAttributeWithNs('svg')); it('xhtml', () => shouldSetAttributeWithNs('xhtml')); 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 { - const namespaceUri = NAMESPACE_URIS[namespace] || namespace; + const namespaceUri = NAMESPACE_URIS[namespace]; const div = document.createElement('div'); expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(false); @@ -48,16 +57,26 @@ import {NAMESPACE_URIS} from '../../src/dom/dom_renderer'; describe('removeAttribute', () => { describe('with namespace', () => { + it('xmlns', () => shouldRemoveAttributeWithNs('xmlns')); it('xml', () => shouldRemoveAttributeWithNs('xml')); it('svg', () => shouldRemoveAttributeWithNs('svg')); it('xhtml', () => shouldRemoveAttributeWithNs('xhtml')); 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 { - const namespaceUri = NAMESPACE_URIS[namespace] || namespace; + const namespaceUri = NAMESPACE_URIS[namespace]; const div = document.createElement('div'); - div.setAttributeNS(namespaceUri, 'name', 'value'); + div.setAttributeNS(namespaceUri, `${namespace}:name`, 'value'); expect(div.hasAttributeNS(namespaceUri, 'name')).toBe(true); renderer.removeAttribute(div, 'name', namespace);