feat(ivy): add namespace instructions for SVG and others (#23899)
PR Close #23899
This commit is contained in:
parent
c494d3cf60
commit
81e4b2a4bf
|
@ -8,24 +8,27 @@
|
|||
|
||||
import './ng_dev_mode';
|
||||
|
||||
import {Sanitizer} from '../sanitization/security';
|
||||
|
||||
import {assertEqual, assertLessThan, assertNotEqual, assertNotNull, assertNull, assertSame} from './assert';
|
||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||
import {executeHooks, executeInitHooks, queueInitHooks, queueLifecycleHooks} from './hooks';
|
||||
import {LContainer} from './interfaces/container';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||
import {LInjector} from './interfaces/injector';
|
||||
import {CssSelectorList, LProjection, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||
import {LQueries} from './interfaces/query';
|
||||
import {ObjectOrientedRenderer3, ProceduralRenderer3, RElement, RText, Renderer3, RendererFactory3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {CurrentMatchesList, LView, LViewFlags, RootContext, TData, TView} from './interfaces/view';
|
||||
|
||||
import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node';
|
||||
import {assertNodeType} from './node_assert';
|
||||
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode, getLViewChild} from './node_manipulation';
|
||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
|
||||
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
|
||||
import {isDifferent, stringify} from './util';
|
||||
import {executeHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks';
|
||||
import {ViewRef} from './view_ref';
|
||||
import {throwCyclicDependencyError, throwErrorIfNoChangesMode, throwMultipleComponentError} from './errors';
|
||||
import {Sanitizer} from '../sanitization/security';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Directive (D) sets a property on all component instances using this constant as a key and the
|
||||
|
@ -550,6 +553,28 @@ function getRenderFlags(view: LView): RenderFlags {
|
|||
RenderFlags.Update;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//// Namespace
|
||||
//////////////////////////
|
||||
let _currentNS: string|null = null;
|
||||
|
||||
export function setNS(namespace: string) {
|
||||
_currentNS = namespace;
|
||||
}
|
||||
|
||||
export function setHtmlNS() {
|
||||
_currentNS = null;
|
||||
}
|
||||
|
||||
export function setSvgNS() {
|
||||
_currentNS = 'http://www.w3.org/2000/svg';
|
||||
}
|
||||
|
||||
export function setMathML() {
|
||||
_currentNS = 'http://www.w3.org/1998/Math/MathML';
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
//// Element
|
||||
//////////////////////////
|
||||
|
@ -573,7 +598,11 @@ export function elementStart(
|
|||
assertEqual(currentView.bindingIndex, -1, 'elements should be created before any bindings');
|
||||
|
||||
ngDevMode && ngDevMode.rendererCreateElement++;
|
||||
const native: RElement = renderer.createElement(name);
|
||||
|
||||
const native: RElement = _currentNS === null || isProceduralRenderer(renderer) ?
|
||||
renderer.createElement(name) :
|
||||
(renderer as ObjectOrientedRenderer3).createElementNS(_currentNS, name);
|
||||
|
||||
ngDevMode && assertDataInRange(index - 1);
|
||||
|
||||
const node: LElementNode =
|
||||
|
|
|
@ -36,6 +36,7 @@ export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3;
|
|||
* */
|
||||
export interface ObjectOrientedRenderer3 {
|
||||
createElement(tagName: string): RElement;
|
||||
createElementNS(namespace: string, name: string): RElement;
|
||||
createTextNode(data: string): RText;
|
||||
|
||||
querySelector(selectors: string): RElement|null;
|
||||
|
|
|
@ -176,6 +176,9 @@
|
|||
{
|
||||
"name": "_currentInjector"
|
||||
},
|
||||
{
|
||||
"name": "_currentNS"
|
||||
},
|
||||
{
|
||||
"name": "_devMode"
|
||||
},
|
||||
|
|
|
@ -1820,7 +1820,7 @@ function declareTests({useJit}: {useJit: boolean}) {
|
|||
.toEqual('http://www.w3.org/2000/svg');
|
||||
|
||||
const firstAttribute = getDOM().getProperty(<Element>use, 'attributes')[0];
|
||||
expect(firstAttribute.name).toEqual('xlink:href');
|
||||
expect(firstAttribute.name).toEqual('href');
|
||||
expect(firstAttribute.namespaceURI).toEqual('http://www.w3.org/1999/xlink');
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,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, 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} 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';
|
||||
|
@ -392,6 +392,40 @@ describe('instructions', () => {
|
|||
expect(s.lastSanitizedValue).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('namespace', () => {
|
||||
it('should render SVG', () => {
|
||||
const t = new TemplateFixture(() => {
|
||||
elementStart(0, 'div', ['id', 'container']);
|
||||
setSvgNS();
|
||||
elementStart(1, 'svg', [
|
||||
// id="display"
|
||||
'id',
|
||||
'display',
|
||||
// width="400"
|
||||
'width',
|
||||
'400',
|
||||
// height="300"
|
||||
'height',
|
||||
'300',
|
||||
]);
|
||||
elementStart(2, 'circle', ['cx', '200', 'cy', '150', 'fill', '#0000ff']);
|
||||
elementEnd();
|
||||
elementEnd();
|
||||
setHtmlNS();
|
||||
elementEnd();
|
||||
});
|
||||
|
||||
|
||||
// Most browsers will print <circle></circle>, some will print <circle />, both are valid
|
||||
const standardHTML =
|
||||
'<div id="container"><svg id="display" width="400" height="300"><circle cx="200" cy="150" fill="#0000ff"></circle></svg></div>';
|
||||
const ie11HTML =
|
||||
'<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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class LocalSanitizedValue {
|
||||
|
|
|
@ -110,7 +110,7 @@ class DefaultDomRenderer2 implements Renderer2 {
|
|||
|
||||
createElement(name: string, namespace?: string): any {
|
||||
if (namespace) {
|
||||
return document.createElementNS(NAMESPACE_URIS[namespace], name);
|
||||
return document.createElementNS(NAMESPACE_URIS[namespace] || namespace, name);
|
||||
}
|
||||
|
||||
return document.createElement(name);
|
||||
|
@ -150,26 +150,17 @@ class DefaultDomRenderer2 implements Renderer2 {
|
|||
|
||||
setAttribute(el: any, name: string, value: string, namespace?: string): void {
|
||||
if (namespace) {
|
||||
name = `${namespace}:${name}`;
|
||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
||||
if (namespaceUri) {
|
||||
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||
el.setAttributeNS(namespaceUri, name, value);
|
||||
} else {
|
||||
el.setAttribute(name, value);
|
||||
}
|
||||
} else {
|
||||
el.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
removeAttribute(el: any, name: string, namespace?: string): void {
|
||||
if (namespace) {
|
||||
const namespaceUri = NAMESPACE_URIS[namespace];
|
||||
if (namespaceUri) {
|
||||
const namespaceUri = NAMESPACE_URIS[namespace] || namespace;
|
||||
el.removeAttributeNS(namespaceUri, name);
|
||||
} else {
|
||||
el.removeAttribute(`${namespace}:${name}`);
|
||||
}
|
||||
} else {
|
||||
el.removeAttribute(name);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue