feat(ivy): now supports SVG and MathML elements (#24377)

- Adds support for ivy creating SVG and MathML elements properly using
createElementNS

PR Close #24377
This commit is contained in:
Ben Lesh
2018-06-08 09:00:01 -07:00
committed by Miško Hevery
parent 5ef7a07c4b
commit 8c1ac28275
11 changed files with 273 additions and 7 deletions

View File

@ -30,6 +30,9 @@ export {
NC as ɵNC,
C as ɵC,
E as ɵE,
NH as ɵNH,
NM as ɵNM,
NS as ɵNS,
L as ɵL,
T as ɵT,
V as ɵV,

View File

@ -150,7 +150,7 @@ The goal is for the `@Component` (and friends) to be the compiler of template. S
| `{{ ['literal', exp ] }}` | ✅ | ✅ | ✅ |
| `{{ { a: 'literal', b: exp } }}` | ✅ | ✅ | ✅ |
| `{{ exp \| pipe: arg }}` | ✅ | ✅ | ✅ |
| `<svg:g svg:p>` | | | |
| `<svg:g svg:p>` | | | |
| `<img src=[userData]>` sanitization | ❌ | ❌ | ❌ |
| `<div (nocd.click)>` | ❌ | ❌ | ❌ |
| `<div (bubble.click)>` | ❌ | ❌ | ❌ |

View File

@ -58,6 +58,10 @@ export {
load as ld,
loadDirective as d,
namespaceHTML as NH,
namespaceMathML as NM,
namespaceSVG as NS,
projection as P,
projectionDef as pD,

View File

@ -495,6 +495,7 @@ export function renderEmbeddedTemplate<T>(
rf = RenderFlags.Create;
}
oldView = enterView(viewNode.data, viewNode);
namespaceHTML();
tView.template !(rf, context);
if (rf & RenderFlags.Update) {
refreshView();
@ -520,6 +521,7 @@ export function renderComponentOrTemplate<T>(
rendererFactory.begin();
}
if (template) {
namespaceHTML();
template(getRenderFlags(hostView), componentOrContext !);
refreshView();
} else {
@ -552,6 +554,24 @@ function getRenderFlags(view: LView): RenderFlags {
RenderFlags.Update;
}
//////////////////////////
//// Namespace
//////////////////////////
let _currentNamespace: string|null = null;
export function namespaceSVG() {
_currentNamespace = 'http://www.w3.org/2000/svg/';
}
export function namespaceMathML() {
_currentNamespace = 'http://www.w3.org/1998/MathML/';
}
export function namespaceHTML() {
_currentNamespace = null;
}
//////////////////////////
//// Element
//////////////////////////
@ -575,7 +595,19 @@ export function elementStart(
assertEqual(currentView.bindingIndex, -1, 'elements should be created before any bindings');
ngDevMode && ngDevMode.rendererCreateElement++;
const native: RElement = renderer.createElement(name);
let native: RElement;
if (isProceduralRenderer(renderer)) {
native = renderer.createElement(name, _currentNamespace);
} else {
if (_currentNamespace === null) {
native = renderer.createElement(name);
} else {
native = renderer.createElementNS(_currentNamespace, name);
}
}
ngDevMode && assertDataInRange(index - 1);
const node: LElementNode =
@ -2130,6 +2162,7 @@ export function detectChangesInternal<T>(hostView: LView, hostNode: LElementNode
const template = hostView.tView.template !;
try {
namespaceHTML();
template(getRenderFlags(hostView), component);
refreshView();
} finally {

View File

@ -36,6 +36,7 @@ export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3;
* */
export interface ObjectOrientedRenderer3 {
createElement(tagName: string): RElement;
createElementNS(namespace: string, tagName: string): RElement;
createTextNode(data: string): RText;
querySelector(selectors: string): RElement|null;

View File

@ -36,6 +36,9 @@ export const angularCoreEnv: {[name: string]: Function} = {
'ɵcR': r3.cR,
'ɵcr': r3.cr,
'ɵd': r3.d,
'ɵNH': r3.NH,
'ɵNM': r3.NM,
'ɵNS': r3.NS,
'ɵE': r3.E,
'ɵe': r3.e,
'ɵf0': r3.f0,