From dc72355f48546ebd36c032497a4e1369e9f2f4ff Mon Sep 17 00:00:00 2001 From: James deBoer Date: Tue, 18 Jun 2013 16:45:49 -0700 Subject: [PATCH] feat(directives): $templateUrl --- demo/web/book.html | 9 ++++++++ demo/web/main.dart | 9 +------- lib/block.dart | 35 +++++++++++++++++++++++------- lib/compiler.dart | 8 ------- lib/directive.dart | 2 ++ lib/http.dart | 2 +- test/_http.dart | 8 ++++++- test/templateurl_spec.dart | 44 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 91 insertions(+), 26 deletions(-) create mode 100644 demo/web/book.html create mode 100644 test/templateurl_spec.dart diff --git a/demo/web/book.html b/demo/web/book.html new file mode 100644 index 000000000..51f1a95d0 --- /dev/null +++ b/demo/web/book.html @@ -0,0 +1,9 @@ +
Shadow backed template. Greeting from the controller: + + +

Table of Contents

+ + +
diff --git a/demo/web/main.dart b/demo/web/main.dart index 0e105b579..82b5b1fbd 100644 --- a/demo/web/main.dart +++ b/demo/web/main.dart @@ -60,14 +60,7 @@ class BookComponent { BookController controller; BookComponent(BookController this.controller); - static String $template = ''' -
Shadow backed template. Greeting from the controller: - -

Table of Contents

- -
'''; + static String $templateUrl = 'book.html'; attach(Scope scope) { controller.attach(scope); diff --git a/lib/block.dart b/lib/block.dart index 609ad2112..916af2da0 100644 --- a/lib/block.dart +++ b/lib/block.dart @@ -179,9 +179,8 @@ class Block implements ElementWrapper { try { var directiveInstance = injector.get(directiveType); if (directiveRef.directive.isComponent) { - // TODO(misko): this way of getting shadowBlock is dumb! - Block shadowBlock = directiveRef.blockTypes[''](); - directiveInstance = new ComponentWrapper(directiveInstance, node, shadowBlock); + directiveInstance = new ComponentWrapper(directiveInstance, node, $injector.get(Compiler), + directiveRef, $injector.get(Http)); } directives.add(directiveInstance); } catch (e,s) { @@ -339,20 +338,40 @@ class Block implements ElementWrapper { class ComponentWrapper { dynamic controller; dom.Element elementRoot; - Block shadowBlock; Scope shadowScope; + Block shadowBlock; - ComponentWrapper(this.controller, this.elementRoot, this.shadowBlock) { + ComponentWrapper(this.controller, this.elementRoot, Compiler $compiler, DirectiveRef directiveRef, Http http) { + var directive = directiveRef.directive; var shadowRoot = elementRoot.createShadowRoot(); - for (var i = 0, ii = shadowBlock.elements.length; i < ii; i++) { - shadowRoot.append(shadowBlock.elements[i]); + + // There is support here for directives having both $template and + // $templateUrl. This could be a clever way to add a 'LOADING' + // message. + if (directive.$template != null) { + shadowRoot.innerHtml = '
${directive.$template}
'; + shadowBlock = $compiler(shadowRoot.nodes)(shadowRoot.nodes); + } + + if (directive.$templateUrl != null) { + http.getString(directive.$templateUrl).then((data) { + shadowRoot.innerHtml = '
${data}
'; + shadowBlock = $compiler(shadowRoot.nodes)(shadowRoot.nodes); + // re-attach the scope. + if (shadowScope != null) { + shadowBlock.attach(shadowScope); + shadowScope.$digest(); + } + }); } } attach(scope) { shadowScope = scope.$new(); controller.attach(shadowScope); - shadowBlock.attach(shadowScope); + if (shadowBlock != null) { + shadowBlock.attach(shadowScope); + } } } diff --git a/lib/compiler.dart b/lib/compiler.dart index bf7fb23e4..99e89e7ef 100644 --- a/lib/compiler.dart +++ b/lib/compiler.dart @@ -65,14 +65,6 @@ class Compiler { } directiveRef.blockTypes = blockTypes; usableDirectiveRefs.add(directiveRef); - if (directive.$template != null) { - // TODO(deboer): port this function. - denormalizeTemplate(x) => x; - var templateValue = denormalizeTemplate(directive.$template); - var div = new dom.DivElement(); - div.innerHtml = templateValue; - directiveRef.blockTypes = {'': this(div.nodes)}; - } } if (compileChildren && domCursor.descend()) { diff --git a/lib/directive.dart b/lib/directive.dart index 192c5ac65..798ef8c61 100644 --- a/lib/directive.dart +++ b/lib/directive.dart @@ -12,6 +12,7 @@ class Directive { int $priority = 0; Type $controllerType; String $template; + String $templateUrl; bool isComponent = false; bool isStructural = false; @@ -40,6 +41,7 @@ class Directive { // It would be awesome if $transclude could be an enum. $transclude = reflectStaticField(type, '\$transclude'); $template = reflectStaticField(type, '\$template'); + $templateUrl = reflectStaticField(type, '\$templateUrl'); $priority = reflectStaticField(type, '\$priority'); if ($priority == null) { $priority = 0; diff --git a/lib/http.dart b/lib/http.dart index 85461cd02..07569912c 100644 --- a/lib/http.dart +++ b/lib/http.dart @@ -2,5 +2,5 @@ part of angular; class Http { async.Future getString(String url, {bool withCredentials, void onProgress(dom.ProgressEvent e)}) => - dom.HttpRequest.getString(url, withCredentials, onProgress); + dom.HttpRequest.getString(url, withCredentials: withCredentials, onProgress: onProgress); } diff --git a/test/_http.dart b/test/_http.dart index 091558c85..e18c72535 100644 --- a/test/_http.dart +++ b/test/_http.dart @@ -7,13 +7,19 @@ import 'package:angular/angular.dart'; class MockHttp extends Http { Map gets = {}; + List futures = []; + expectGET(url, content) { gets[url] = content; } + flush() => Future.wait(futures); + Future getString(String url, {bool withCredentials, void onProgress(ProgressEvent e)}) { if (!gets.containsKey(url)) throw "Unexpected URL $url"; - return new Future.value(gets.remove(url)); + var f = new Future.value(gets.remove(url)); + futures.add(f); + return f; } } diff --git a/test/templateurl_spec.dart b/test/templateurl_spec.dart new file mode 100644 index 000000000..74755186c --- /dev/null +++ b/test/templateurl_spec.dart @@ -0,0 +1,44 @@ +import "_specs.dart"; +import "_log.dart"; +import "_http.dart"; + +class LogAttrDirective { + static var $priority = 0; + Log log; + LogAttrDirective(Log this.log, DirectiveValue value) { + log(value.value == "" ? "LOG" : value.value); + } + attach(Scope scope) {} +} + +class SimpleUrlComponent { + static String $templateUrl = 'simple.html'; + attach(Scope scope) {} +} + +main() { + describe('templateUrl', () { + beforeEach(module((module) { + var mockHttp = new MockHttp(); + module.value(MockHttp, mockHttp); + module.value(Http, mockHttp); + module.directive(LogAttrDirective); + module.directive(SimpleUrlComponent); + })); + + it('should replace element with template from url', inject((MockHttp $http, Compiler $compile, Scope $rootScope, Log log) { + $http.expectGET('simple.html', '
Simple!
'); + + var element = $('
ignore
'); + $compile(element)(element)..attach($rootScope); + + $http.flush().then(expectAsync1((data) { + expect(renderedText(element)).toEqual('Simple!'); + // Note: There is no ordering. It is who ever comes off the wire first! + expect(log.result()).toEqual('LOG; SIMPLE'); + })); + + })); + }); +} +