Skip to content

Commit 6e655d1

Browse files
committed
feat(Component): add namespaceUri parameter so Components can be placed in SVG
1 parent f56a272 commit 6e655d1

9 files changed

+694
-10
lines changed

example/web/logo.svg

+588
Loading

example/web/svg_component.dart

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'dart:html';
2+
3+
import 'package:angular/angular.dart';
4+
import 'package:angular/animate/module.dart';
5+
import 'package:angular/application_factory.dart';
6+
import 'package:di/di.dart';
7+
8+
main() {
9+
var app = applicationFactory();
10+
app.modules.add(new Module()
11+
..bind(AngularDartLogo));
12+
app.selector("body");
13+
app.run();
14+
}
15+
16+
@Component(
17+
selector: "g[angular-dart-logo]",
18+
publishAs: "ctrl",
19+
templateUrl: "logo.svg",
20+
useShadowDom: false,
21+
namespaceUri: "http://www.w3.org/2000/svg")
22+
class AngularDartLogo {}

example/web/svg_component.html

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
3+
<html>
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>SVG Component test page</title>
8+
<style>
9+
body {
10+
margin: 0;
11+
/* Extra spacing at top and bottom */
12+
padding: 20px 20px 0 20px;
13+
min-height: 100%;
14+
font-family: sans-serif;
15+
}
16+
[ng-cloak] {
17+
display: none;
18+
}
19+
</style>
20+
21+
<script src="packages/web_components/platform.js"></script>
22+
<script src="packages/web_components/dart_support.js"></script>
23+
</head>
24+
25+
<body>
26+
<p ng-if="false">Just waiting for this demo app to load...</p>
27+
<div class="content" ng-cloak>
28+
<h1>Hi</h1>
29+
30+
<p>There should be <strong>one</strong> component here. The AngularDart logo
31+
rendered in SVG.</p>
32+
33+
<svg width="610px" height="125px">
34+
<g angular-dart-logo></g>
35+
</svg>
36+
</div>
37+
<script type="application/dart" src="svg_component.dart"></script>
38+
<script src="packages/browser/dart.js"></script>
39+
</body>
40+
</html>

lib/core/annotation_src.dart

+8
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ class Component extends Directive {
293293
}
294294
final bool _resetStyleInheritance;
295295

296+
/**
297+
* The namespaceUri elements are created with. This allows components to be
298+
* placed inside SVG.
299+
*/
300+
final String namespaceUri;
301+
296302
/**
297303
* An expression under which the component's controller instance will be
298304
* published into. This allows the expressions in the template to be referring
@@ -325,6 +331,7 @@ class Component extends Directive {
325331
visibility,
326332
exportExpressions,
327333
exportExpressionAttrs,
334+
this.namespaceUri: "",
328335
this.useShadowDom,
329336
this.useNgBaseCss: true})
330337
: _cssUrls = cssUrl,
@@ -356,6 +363,7 @@ class Component extends Directive {
356363
visibility: visibility,
357364
exportExpressions: exportExpressions,
358365
exportExpressionAttrs: exportExpressionAttrs,
366+
namespaceUri: namespaceUri,
359367
useShadowDom: useShadowDom,
360368
useNgBaseCss: useNgBaseCss);
361369
}

lib/core_dom/shadow_dom_component_factory.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ abstract class BoundComponentFactory {
1414
static async.Future<ViewFactory> _viewFuture(
1515
Component component, ViewCache viewCache, DirectiveMap directives) {
1616
if (component.template != null) {
17-
return new async.Future.value(viewCache.fromHtml(component.template, directives));
17+
return new async.Future.value(viewCache.fromHtml(component.template, directives,
18+
component.namespaceUri));
1819
}
1920
if (component.templateUrl != null) {
20-
return viewCache.fromUrl(component.templateUrl, directives);
21+
return viewCache.fromUrl(component.templateUrl, directives, component.namespaceUri);
2122
}
2223
return null;
2324
}

lib/core_dom/view_factory.dart

+5-4
Original file line numberDiff line numberDiff line change
@@ -139,22 +139,23 @@ class ViewCache {
139139
cacheRegister.registerCache('ViewCache', viewFactoryCache);
140140
}
141141

142-
ViewFactory fromHtml(String html, DirectiveMap directives) {
142+
ViewFactory fromHtml(String html, DirectiveMap directives, [String namespaceUri = ""]) {
143143
ViewFactory viewFactory = viewFactoryCache.get(html);
144144
if (viewFactory == null) {
145-
var div = new dom.DivElement();
145+
var div = dom.document.createElementNS(namespaceUri, "div");
146146
div.setInnerHtml(html, treeSanitizer: treeSanitizer);
147147
viewFactory = compiler(div.nodes, directives);
148148
viewFactoryCache.put(html, viewFactory);
149149
}
150150
return viewFactory;
151151
}
152152

153-
async.Future<ViewFactory> fromUrl(String url, DirectiveMap directives) {
153+
async.Future<ViewFactory> fromUrl(String url, DirectiveMap directives,
154+
[String namespaceUri = ""]) {
154155
ViewFactory viewFactory = viewFactoryCache.get(url);
155156
if (viewFactory == null) {
156157
return http.get(url, cache: templateCache).then((resp) {
157-
var viewFactoryFromHttp = fromHtml(resp.responseText, directives);
158+
var viewFactoryFromHttp = fromHtml(resp.responseText, directives, namespaceUri);
158159
viewFactoryCache.put(url, viewFactoryFromHttp);
159160
return viewFactoryFromHttp;
160161
});

lib/core_dom/web_platform.dart

+5-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class PlatformViewCache implements ViewCache {
6363

6464
PlatformViewCache(this.cache, this.selector, this.platform);
6565

66-
ViewFactory fromHtml(String html, DirectiveMap directives) {
66+
ViewFactory fromHtml(String html, DirectiveMap directives, [String namespaceUri = ""]) {
6767
ViewFactory viewFactory;
6868

6969
if (selector != null && selector != "" && platform.shadowDomShimRequired) {
@@ -75,7 +75,7 @@ class PlatformViewCache implements ViewCache {
7575
}
7676

7777
if (viewFactory == null) {
78-
var div = new dom.DivElement();
78+
var div = dom.document.createElementNS(namespaceUri, "div");
7979
div.setInnerHtml(html, treeSanitizer: treeSanitizer);
8080

8181
if (selector != null && selector != "" && platform.shadowDomShimRequired) {
@@ -90,12 +90,13 @@ class PlatformViewCache implements ViewCache {
9090
return viewFactory;
9191
}
9292

93-
async.Future<ViewFactory> fromUrl(String url, DirectiveMap directives) {
93+
async.Future<ViewFactory> fromUrl(String url, DirectiveMap directives,
94+
[String namespaceUri = ""]) {
9495
var key = "[$selector]$url";
9596
ViewFactory viewFactory = viewFactoryCache.get(key);
9697
if (viewFactory == null) {
9798
return http.get(url, cache: templateCache).then((resp) {
98-
var viewFactoryFromHttp = fromHtml(resp.responseText, directives);
99+
var viewFactoryFromHttp = fromHtml(resp.responseText, directives, namespaceUri);
99100
viewFactoryCache.put(key, viewFactoryFromHttp);
100101
return viewFactoryFromHttp;
101102
});

test_e2e/examplesConf.js

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ var config = {
1818
specs: [
1919
'animation_spec.dart',
2020
'hello_world_spec.dart',
21+
'svg_component_spec.dart',
2122
'todo_spec.dart'
2223
],
2324

test_e2e/svg_component_spec.dart

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'dart:html';
2+
import 'package:js/js.dart';
3+
import 'package:protractor/protractor_api.dart';
4+
5+
main() {
6+
describe('svg_component example', () {
7+
8+
beforeEach(() {
9+
protractor.getInstance().get('svg_component.html');
10+
});
11+
12+
it('should have an SVG image element', () {
13+
/*
14+
* It seems like the image element is transformed to a img element if the correct
15+
* namespace have not been specified so just testing if a image element exists or not
16+
* should be enough.
17+
*/
18+
expect(element(by.css('svg g image'))).not.toBeNull();
19+
});
20+
21+
});
22+
}

0 commit comments

Comments
 (0)