X Tutup
Skip to content

Commit ac52bfd

Browse files
committed
fix(render): create svg elements with the right namespace
Temporary fix for #4506 Closes #4949
1 parent 27dbd2d commit ac52bfd

File tree

7 files changed

+147
-5
lines changed

7 files changed

+147
-5
lines changed

modules/angular2/src/core/dom/abstract_html_adapter.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ abstract class AbstractHtml5LibAdapter implements DomAdapter {
215215
return new Element.tag(tagName);
216216
}
217217

218+
createElementNS(ns, tagName, [doc]) {
219+
throw 'not implemented';
220+
}
221+
218222
createTextNode(String text, [doc]) => new Text(text);
219223

220224
createScriptTag(String attrName, String attrValue, [doc]) {
@@ -297,6 +301,10 @@ abstract class AbstractHtml5LibAdapter implements DomAdapter {
297301
element.attributes[name] = value;
298302
}
299303

304+
setAttributeNS(element, String ns, String name, String value) {
305+
throw 'not implemented';
306+
}
307+
300308
removeAttribute(element, String attribute) {
301309
element.attributes.remove(attribute);
302310
}

modules/angular2/src/core/dom/browser_adapter.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
287287
return doc.createElement(tagName);
288288
}
289289

290+
Element createElementNS(String ns, String tagName, [HtmlDocument doc = null]) {
291+
if (doc == null) doc = document;
292+
return doc.createElementNS(ns, tagName);
293+
}
294+
290295
Text createTextNode(String text, [HtmlDocument doc = null]) {
291296
return new Text(text);
292297
}
@@ -354,6 +359,10 @@ class BrowserDomAdapter extends GenericBrowserDomAdapter {
354359
element.setAttribute(name, value);
355360
}
356361

362+
void setAttributeNS(Element element, String ns, String name, String value) {
363+
element.setAttributeNS(ns, name, value);
364+
}
365+
357366
void removeAttribute(Element element, String name) {
358367
//there is no removeAttribute method as of now in Dart:
359368
//https://code.google.com/p/dart/issues/detail?id=19934

modules/angular2/src/core/dom/browser_adapter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
182182
return t;
183183
}
184184
createElement(tagName, doc = document): HTMLElement { return doc.createElement(tagName); }
185+
createElementNS(ns, tagName, doc = document): Element { return doc.createElementNS(ns, tagName); }
185186
createTextNode(text: string, doc = document): Text { return doc.createTextNode(text); }
186187
createScriptTag(attrName: string, attrValue: string, doc = document): HTMLScriptElement {
187188
var el = <HTMLScriptElement>doc.createElement('SCRIPT');
@@ -225,6 +226,9 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
225226
hasAttribute(element, attribute: string): boolean { return element.hasAttribute(attribute); }
226227
getAttribute(element, attribute: string): string { return element.getAttribute(attribute); }
227228
setAttribute(element, name: string, value: string) { element.setAttribute(name, value); }
229+
setAttributeNS(ns: string, element, name: string, value: string) {
230+
element.setAttributeNS(ns, name, value);
231+
}
228232
removeAttribute(element, attribute: string) { element.removeAttribute(attribute); }
229233
templateAwareRoot(el): any { return this.isTemplateElement(el) ? this.content(el) : el; }
230234
createHtmlDocument(): HTMLDocument {

modules/angular2/src/core/dom/dom_adapter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export abstract class DomAdapter {
7171
abstract createComment(text: string): any;
7272
abstract createTemplate(html): HTMLElement;
7373
abstract createElement(tagName, doc?): HTMLElement;
74+
abstract createElementNS(ns: string, tagName: string, doc?): Element;
7475
abstract createTextNode(text: string, doc?): Text;
7576
abstract createScriptTag(attrName: string, attrValue: string, doc?): HTMLElement;
7677
abstract createStyleElement(css: string, doc?): HTMLStyleElement;
@@ -93,6 +94,7 @@ export abstract class DomAdapter {
9394
abstract hasAttribute(element, attribute: string): boolean;
9495
abstract getAttribute(element, attribute: string): string;
9596
abstract setAttribute(element, name: string, value: string);
97+
abstract setAttributeNS(element, ns: string, name: string, value: string);
9698
abstract removeAttribute(element, attribute: string);
9799
abstract templateAwareRoot(el);
98100
abstract createHtmlDocument(): HTMLDocument;

modules/angular2/src/core/dom/parse5_adapter.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ export class Parse5DomAdapter extends DomAdapter {
276276
createElement(tagName): HTMLElement {
277277
return treeAdapter.createElement(tagName, 'http://www.w3.org/1999/xhtml', []);
278278
}
279+
createElementNS(ns, tagName): HTMLElement { throw 'not implemented'; }
279280
createTextNode(text: string): Text {
280281
var t = <any>this.createComment(text);
281282
t.type = 'text';
@@ -435,6 +436,7 @@ export class Parse5DomAdapter extends DomAdapter {
435436
}
436437
}
437438
}
439+
setAttributeNS(element, ns: string, attribute: string, value: string) { throw 'not implemented'; }
438440
removeAttribute(element, attribute: string) {
439441
if (attribute) {
440442
StringMapWrapper.delete(element.attribs, attribute);

modules/angular2/src/core/render/dom/dom_renderer.ts

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,92 @@ import {createRenderView, NodeFactory} from '../view_factory';
3232
import {DefaultRenderView, DefaultRenderFragmentRef, DefaultProtoViewRef} from '../view';
3333
import {camelCaseToDashCase} from './util';
3434

35+
// TODO(tbosch): solve SVG properly once https://github.com/angular/angular/issues/4417 is done
36+
const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
37+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
38+
const SVG_ELEMENT_NAMES = CONST_EXPR({
39+
'altGlyph': true,
40+
'altGlyphDef': true,
41+
'altGlyphItem': true,
42+
'animate': true,
43+
'animateColor': true,
44+
'animateMotion': true,
45+
'animateTransform': true,
46+
'circle': true,
47+
'clipPath': true,
48+
'color-profile': true,
49+
'cursor': true,
50+
'defs': true,
51+
'desc': true,
52+
'ellipse': true,
53+
'feBlend': true,
54+
'feColorMatrix': true,
55+
'feComponentTransfer': true,
56+
'feComposite': true,
57+
'feConvolveMatrix': true,
58+
'feDiffuseLighting': true,
59+
'feDisplacementMap': true,
60+
'feDistantLight': true,
61+
'feFlood': true,
62+
'feFuncA': true,
63+
'feFuncB': true,
64+
'feFuncG': true,
65+
'feFuncR': true,
66+
'feGaussianBlur': true,
67+
'feImage': true,
68+
'feMerge': true,
69+
'feMergeNode': true,
70+
'feMorphology': true,
71+
'feOffset': true,
72+
'fePointLight': true,
73+
'feSpecularLighting': true,
74+
'feSpotLight': true,
75+
'feTile': true,
76+
'feTurbulence': true,
77+
'filter': true,
78+
'font': true,
79+
'font-face': true,
80+
'font-face-format': true,
81+
'font-face-name': true,
82+
'font-face-src': true,
83+
'font-face-uri': true,
84+
'foreignObject': true,
85+
'g': true,
86+
'glyph': true,
87+
'glyphRef': true,
88+
'hkern': true,
89+
'image': true,
90+
'line': true,
91+
'linearGradient': true,
92+
'marker': true,
93+
'mask': true,
94+
'metadata': true,
95+
'missing-glyph': true,
96+
'mpath': true,
97+
'path': true,
98+
'pattern': true,
99+
'polygon': true,
100+
'polyline': true,
101+
'radialGradient': true,
102+
'rect': true,
103+
'set': true,
104+
'stop': true,
105+
'style': true,
106+
'svg': true,
107+
'switch': true,
108+
'symbol': true,
109+
'text': true,
110+
'textPath': true,
111+
'title': true,
112+
'tref': true,
113+
'tspan': true,
114+
'use': true,
115+
'view': true,
116+
'vkern': true
117+
});
118+
119+
const SVG_ATTR_NAMESPACES = CONST_EXPR({'href': XLINK_NAMESPACE});
120+
35121
export abstract class DomRenderer extends Renderer implements NodeFactory<Node> {
36122
abstract registerComponentTemplate(templateId: number, commands: RenderTemplateCmd[],
37123
styles: string[], nativeShadow: boolean);
@@ -271,17 +357,25 @@ export class DomRenderer_ extends DomRenderer {
271357
wtfLeave(s);
272358
}
273359
createElement(name: string, attrNameAndValues: string[]): Node {
274-
var el = DOM.createElement(name);
275-
this._setAttributes(el, attrNameAndValues);
360+
var isSvg = SVG_ELEMENT_NAMES[name] == true;
361+
var el = isSvg ? DOM.createElementNS(SVG_NAMESPACE, name) : DOM.createElement(name);
362+
this._setAttributes(el, attrNameAndValues, isSvg);
276363
return el;
277364
}
278365
mergeElement(existing: Node, attrNameAndValues: string[]) {
279366
DOM.clearNodes(existing);
280-
this._setAttributes(existing, attrNameAndValues);
367+
this._setAttributes(existing, attrNameAndValues, false);
281368
}
282-
private _setAttributes(node: Node, attrNameAndValues: string[]) {
369+
private _setAttributes(node: Node, attrNameAndValues: string[], isSvg: boolean) {
283370
for (var attrIdx = 0; attrIdx < attrNameAndValues.length; attrIdx += 2) {
284-
DOM.setAttribute(node, attrNameAndValues[attrIdx], attrNameAndValues[attrIdx + 1]);
371+
var attrName = attrNameAndValues[attrIdx];
372+
var attrValue = attrNameAndValues[attrIdx + 1];
373+
var attrNs = isSvg ? SVG_ATTR_NAMESPACES[attrName] : null;
374+
if (isPresent(attrNs)) {
375+
DOM.setAttributeNS(node, XLINK_NAMESPACE, attrName, attrValue);
376+
} else {
377+
DOM.setAttribute(node, attrName, attrValue);
378+
}
285379
}
286380
}
287381
createRootContentInsertionPoint(): Node {

modules/angular2/test/core/linker/integration_spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,29 @@ export function main() {
17411741
});
17421742
}));
17431743
});
1744+
1745+
if (DOM.supportsDOMEvents()) {
1746+
describe('svg', () => {
1747+
it('should support svg elements',
1748+
inject([TestComponentBuilder, AsyncTestCompleter],
1749+
(tcb: TestComponentBuilder, async) => {
1750+
tcb.overrideView(MyComp, new ViewMetadata({template: '<svg><g></g></svg>'}))
1751+
.createAsync(MyComp)
1752+
.then((rootTC) => {
1753+
var el = rootTC.debugElement.nativeElement;
1754+
var svg = DOM.childNodes(el)[0];
1755+
var g = DOM.childNodes(svg)[0];
1756+
expect(DOM.getProperty(<Element>svg, 'namespaceURI'))
1757+
.toEqual('http://www.w3.org/2000/svg');
1758+
expect(DOM.getProperty(<Element>g, 'namespaceURI'))
1759+
.toEqual('http://www.w3.org/2000/svg');
1760+
1761+
async.done();
1762+
});
1763+
}));
1764+
1765+
});
1766+
}
17441767
});
17451768
}
17461769

0 commit comments

Comments
 (0)
X Tutup