@@ -108,8 +108,8 @@ class Block implements ElementWrapper {
108
108
if (ref.directive.isComponent) {
109
109
//nodeModule.factory(type, new ComponentFactory(node, ref.directive), visibility: visibility);
110
110
// TODO(misko): there should be no need to wrap function like this.
111
- nodeModule.factory (type, (Injector injector, Compiler compiler, Scope scope, Parser parser, Http $http ) =>
112
- (new ComponentFactory (node, ref.directive))(injector, compiler, scope, parser, $http ),
111
+ nodeModule.factory (type, (Injector injector, Compiler compiler, Scope scope, Parser parser, BlockCache $blockCache ) =>
112
+ (new ComponentFactory (node, ref.directive))(injector, compiler, scope, parser, $blockCache ),
113
113
visibility: visibility);
114
114
} else {
115
115
nodeModule.type (type, type, visibility: visibility);
@@ -266,36 +266,45 @@ class ComponentFactory {
266
266
267
267
ComponentFactory (this .element, this .directive);
268
268
269
- dynamic call (Injector injector, Compiler compiler, Scope scope, Parser parser, Http $http) {
269
+ dynamic call (Injector injector, Compiler compiler, Scope scope,
270
+ Parser parser, BlockCache $blockCache) {
270
271
this .compiler = compiler;
271
272
shadowDom = element.createShadowRoot ();
272
273
shadowScope = scope.$new (true );
273
274
createAttributeMapping (scope, shadowScope, parser);
274
- var controller = createShadowInjector (injector).get (directive.type);
275
275
if (directive.$cssUrl != null ) {
276
276
shadowDom.innerHtml = '<style>@import "${directive .$cssUrl }"</style>' ;
277
277
}
278
+ TemplateLoader templateLoader;
278
279
if (directive.$template != null ) {
279
- compileTemplate (directive.$template);
280
+ var blockFuture = new async .Future .value ().then ((_) =>
281
+ attachBlockToShadowDom ($blockCache.fromHtml (directive.$template)));
282
+ templateLoader = new TemplateLoader (blockFuture);
280
283
} else if (directive.$templateUrl != null ) {
281
- $http.
282
- getString (directive.$templateUrl).
283
- then ((data) => shadowScope. $apply (() => compileTemplate (data)) );
284
+ var blockFuture = $blockCache. fromUrl (directive.$templateUrl)
285
+ . then (( BlockType blockType) => attachBlockToShadowDom (blockType));
286
+ templateLoader = new TemplateLoader (blockFuture );
284
287
}
288
+ var controller =
289
+ createShadowInjector (injector, templateLoader).get (directive.type);
285
290
if (directive.$publishAs != null ) {
286
291
shadowScope[directive.$publishAs] = controller;
287
292
}
288
293
return controller;
289
294
}
290
295
291
- compileTemplate (html) {
292
- shadowDom.innerHtml += html;
293
- compiler (shadowDom.nodes)(shadowInjector, shadowDom.nodes);
296
+ attachBlockToShadowDom (BlockType blockType) {
297
+ var block = blockType (shadowInjector);
298
+ shadowDom.nodes.addAll (block.elements);
299
+ shadowInjector.get (Scope ).$digest ();
300
+ return shadowDom;
294
301
}
295
302
296
- createShadowInjector (injector) {
297
- var shadowModule = new ScopeModule (shadowScope);
298
- shadowModule.type (directive.type, directive.type);
303
+ createShadowInjector (injector, TemplateLoader templateLoader) {
304
+ var shadowModule = new ScopeModule (shadowScope)
305
+ ..type (directive.type, directive.type)
306
+ ..value (TemplateLoader , templateLoader)
307
+ ..value (dom.ShadowRoot , shadowDom);
299
308
shadowInjector = injector.createChild ([shadowModule]);
300
309
// TODO(misko): creazy hack to mark injector
301
310
shadowInjector.instances[_SHADOW ] = injector;
@@ -333,18 +342,70 @@ class ComponentFactory {
333
342
}
334
343
}
335
344
345
+ class BlockCache {
346
+ Cache _blockCache;
347
+ Http $http;
348
+ TemplateCache $templateCache;
349
+ Compiler compiler;
350
+
351
+ BlockCache (CacheFactory $cacheFactory, Http this .$http,
352
+ TemplateCache this .$templateCache, Compiler this .compiler) {
353
+ _blockCache = $cacheFactory ('blocks' );
354
+ }
355
+
356
+ BlockType fromHtml (String html) {
357
+ BlockType blockType = _blockCache.get (html);
358
+ if (blockType == null ) {
359
+ var div = new dom.Element .tag ('div' );
360
+ div.innerHtml = html;
361
+ blockType = compiler (div.nodes);
362
+ _blockCache.put (html, blockType);
363
+ }
364
+ return blockType;
365
+ }
366
+
367
+ async .Future <BlockType > fromUrl (String url) {
368
+ return $http.getString (url, cache: $templateCache).then ((String tmpl) {
369
+ return fromHtml (tmpl);
370
+ });
371
+ }
372
+ }
373
+
374
+ /**
375
+ * A convinience wrapper for "templates" cache.
376
+ */
377
+ class TemplateCache implements Cache {
378
+ Cache _cache;
379
+
380
+ TemplateCache (CacheFactory $cacheFactory) {
381
+ _cache = $cacheFactory ('templates' );
382
+ }
383
+
384
+ Object get (key) => _cache.get (key);
385
+ Object put (key, Object value) => _cache.put (key, value);
386
+ void remove (key) => _cache.remove (key);
387
+ void removeAll () => _cache.removeAll ();
388
+ CacheInfo info () => _cache.info ();
389
+ void destroy () => _cache.destroy ();
390
+ }
391
+
392
+ class TemplateLoader {
393
+ final async .Future <dom.ShadowRoot > _template;
394
+ async .Future <dom.ShadowRoot > get template => _template;
395
+ TemplateLoader (this ._template);
396
+ }
336
397
337
398
attrAccessorFactory (dom.Element element, String name) {
338
399
return ([String value]) {
339
400
if (value != null ) {
340
401
if (value == null ) {
341
- element.removeAttribute (name);
402
+ element.attributes. remove (name);
342
403
} else {
343
- element.setAttribute ( name, value) ;
404
+ element.attributes[ name] = value;
344
405
}
345
406
return value;
346
407
} else {
347
- return element.getAttribute ( name) ;
408
+ return element.attributes[ name] ;
348
409
}
349
410
};
350
411
}
0 commit comments