From e2591cca36c553c89d01c243262675fdc1511b67 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 24 Apr 2014 14:20:39 +0200 Subject: [PATCH 01/29] Update demos --- example/web/animation.dart | 4 +--- example/web/animation.html | 8 ++++---- example/web/animation/css_demo.dart | 18 ++++++++-------- example/web/animation/repeat_demo.dart | 9 ++++---- example/web/animation/stress_demo.dart | 4 ++-- example/web/animation/visibility_demo.dart | 6 +++--- example/web/bouncing_balls.dart | 4 +--- example/web/bouncing_balls.html | 24 +++++++++++----------- example/web/hello_world.dart | 4 +--- example/web/hello_world.html | 4 ++-- example/web/todo.dart | 4 +--- example/web/todo.html | 14 ++++++------- 12 files changed, 47 insertions(+), 56 deletions(-) diff --git a/example/web/animation.dart b/example/web/animation.dart index a60f569d2..67484d35c 100644 --- a/example/web/animation.dart +++ b/example/web/animation.dart @@ -9,9 +9,7 @@ part 'animation/visibility_demo.dart'; part 'animation/stress_demo.dart'; part 'animation/css_demo.dart'; -@Controller( - selector: '[animation-demo]', - publishAs: 'demo') +@Controller(selector: '[animation-demo]') class AnimationDemo { final pages = ["About", "ng-repeat", "Visibility", "Css", "Stress Test"]; var currentPage = "About"; diff --git a/example/web/animation.html b/example/web/animation.html index d0728b00b..ddc5e5d41 100644 --- a/example/web/animation.html +++ b/example/web/animation.html @@ -6,13 +6,13 @@ -
+

About

The NgAnimate module is a port with modifications of the original diff --git a/example/web/animation/css_demo.dart b/example/web/animation/css_demo.dart index a09018595..4814bdef9 100644 --- a/example/web/animation/css_demo.dart +++ b/example/web/animation/css_demo.dart @@ -4,20 +4,20 @@ part of animation; selector: 'css-demo', template: '''

- - -
BOX
+ 'a': stateA, + 'b': stateB, + 'c': stateC}">BOX
diff --git a/example/web/animation/repeat_demo.dart b/example/web/animation/repeat_demo.dart index 5857d72fe..262e80cd6 100644 --- a/example/web/animation/repeat_demo.dart +++ b/example/web/animation/repeat_demo.dart @@ -4,13 +4,12 @@ part of animation; selector: 'repeat-demo', template: '''
- - + +
    -
  • +
    • -
    • {{inner}}
    • +
    • {{inner}}
diff --git a/example/web/animation/stress_demo.dart b/example/web/animation/stress_demo.dart index 2f9b9a488..850912dd1 100644 --- a/example/web/animation/stress_demo.dart +++ b/example/web/animation/stress_demo.dart @@ -4,10 +4,10 @@ part of animation; selector: 'stress-demo', template: '''
-
-
+
''', diff --git a/example/web/animation/visibility_demo.dart b/example/web/animation/visibility_demo.dart index 5dee51f2a..05dd60ea8 100644 --- a/example/web/animation/visibility_demo.dart +++ b/example/web/animation/visibility_demo.dart @@ -4,12 +4,12 @@ part of animation; selector: 'visibility-demo', template: '''
- -
+ +

Hello World. ng-if will create and destroy dom elements each time you toggle me.

-
+

Hello World. ng-hide will add and remove the .ng-hide class from me to show and hide this view of text.

diff --git a/example/web/bouncing_balls.dart b/example/web/bouncing_balls.dart index d2d3ca3a4..2df0eba53 100644 --- a/example/web/bouncing_balls.dart +++ b/example/web/bouncing_balls.dart @@ -26,9 +26,7 @@ class BallModel { } -@Controller( - selector: '[bounce-controller]', - publishAs: 'bounce') +@Controller(selector: '[bounce-controller]') class BounceController { var lastTime = window.performance.now(); var run = false; diff --git a/example/web/bouncing_balls.html b/example/web/bouncing_balls.html index 7ba8f7316..fa7c8b8a5 100644 --- a/example/web/bouncing_balls.html +++ b/example/web/bouncing_balls.html @@ -39,30 +39,30 @@
-
-
+
{{bounce.fps}} fps. ({{bounce.balls.length}} balls) [{{1000/bounce.fps}} ms]
Digest: {{bounce.digestTime}} ms
- +1 - +10 - +100 + +1 + +10 + +100
- -1 - -10 - -100 + -1 + -10 + -100
- ▶❙❙
- Toggle CSS
- noop
+ ▶❙❙
+ Toggle CSS
+ noop
diff --git a/example/web/hello_world.dart b/example/web/hello_world.dart index ab8953f72..53fbfb615 100644 --- a/example/web/hello_world.dart +++ b/example/web/hello_world.dart @@ -1,9 +1,7 @@ import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -@Controller( - selector: '[hello-world-controller]', - publishAs: 'ctrl') +@Controller(selector: '[hello-world-controller]') class HelloWorld { String name = "world"; } diff --git a/example/web/hello_world.html b/example/web/hello_world.html index 1b4c681d9..475238794 100644 --- a/example/web/hello_world.html +++ b/example/web/hello_world.html @@ -5,8 +5,8 @@ -

Hello {{ctrl.name}}!

-name: +

Hello {{name}}!

+name: diff --git a/example/web/todo.dart b/example/web/todo.dart index b4c1c7bbb..d415f25a9 100644 --- a/example/web/todo.dart +++ b/example/web/todo.dart @@ -54,9 +54,7 @@ class HttpServer implements Server { } -@Controller( - selector: '[todo-controller]', - publishAs: 'todo') +@Controller(selector: '[todo-controller]') class Todo { var items = []; Item newItem; diff --git a/example/web/todo.html b/example/web/todo.html index cbd32cc92..605912a24 100644 --- a/example/web/todo.html +++ b/example/web/todo.html @@ -15,15 +15,15 @@

Things To Do ;-)

- - + +
-

Remaining {{todo.remaining()}} of {{todo.items.length}} items.

+

Remaining {{ remaining() }} of {{ items.length }} items.

    -
  • +
  • @@ -31,9 +31,9 @@

    Things To Do ;-)

- - - + + +
From cd9f7e30dba049411f1a4b37437a7b25e56d4642 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 24 Apr 2014 14:23:47 +0200 Subject: [PATCH 02/29] minor --- benchmark/lexer_perf.dart | 18 +++++-------- lib/animate/module.dart | 27 +++++++++---------- lib/core_dom/event_handler.dart | 10 ++++--- .../transcluding_component_factory.dart | 13 +++++---- lib/directive/module.dart | 2 +- lib/directive/ng_if.dart | 2 +- 6 files changed, 33 insertions(+), 39 deletions(-) diff --git a/benchmark/lexer_perf.dart b/benchmark/lexer_perf.dart index 80aff438d..65533f48d 100644 --- a/benchmark/lexer_perf.dart +++ b/benchmark/lexer_perf.dart @@ -5,16 +5,10 @@ import 'package:angular/core/parser/lexer.dart'; main() { Lexer lexer = new Lexer(); - time('ident', () => - lexer.call('ctrl foo baz ctrl.foo ctrl.bar ctrl.baz')); - time('ident-path', () => - lexer.call('a.b a.b.c a.b.c.d a.b.c.d.e.f')); - time('num', () => - lexer.call('1 23 34 456 12341234 12351235')); - time('num-double', () => - lexer.call('.0 .1 .12 0.123 0.1234')); - time('string', () => - lexer.call("'quick brown dog and fox say what'")); - time('string-escapes', () => - lexer.call("quick '\\' brown \u1234 dog and fox\n\rsay what'")); + time('ident', () => lexer.call('ctrl foo baz ctrl.foo ctrl.bar ctrl.baz')); + time('ident-path', () => lexer.call('a.b a.b.c a.b.c.d a.b.c.d.e.f')); + time('num', () => lexer.call('1 23 34 456 12341234 12351235')); + time('num-double', () => lexer.call('.0 .1 .12 0.123 0.1234')); + time('string', () => lexer.call("'quick brown dog and fox say what'")); + time('string-escapes', () => lexer.call("quick '\\' brown \u1234 dog and fox\n\rsay what'")); } diff --git a/lib/animate/module.dart b/lib/animate/module.dart index 44a700613..119fa5ba8 100644 --- a/lib/animate/module.dart +++ b/lib/animate/module.dart @@ -4,11 +4,11 @@ * The [angular.animate](#angular/angular-animate) library makes it easier to build animations * that affect the lifecycle of DOM elements. A useful example of this is animating the * removal of an element from the DOM. In order to do this ideally the - * operation should immediatly execute and manipulate the data model, + * operation should immediately execute and manipulate the data model, * and the framework should handle the actual remove of the DOM element once - * the animation complets. This ensures that the logic and model of the - * application is seperated so that the state of the model can be reasoned - * about without having to wory about future modifications of the model. + * the animation completes. This ensures that the logic and model of the + * application is separated so that the state of the model can be reasoned + * about without having to worry about future modifications of the model. * This library uses computed css styles to calculate the total duration * of an animation and handles the addition, removal, and modification of DOM * elements for block level directives such as `ng-if`, `ng-repeat`, @@ -16,15 +16,14 @@ * * To use, install the AnimationModule into your main module: * - * var module = new Module() - * ..install(new AnimationModule()); + * var module = new Module()..install(new AnimationModule()); * * Once the module has been installed, all block level DOM manipulations will * be routed through the [CssAnimate] class instead of the * default [NgAnimate] implementation. This will, in turn, * perform the tracking, manipulation, and computation for animations. * - * As an example of how this works, let's walk through what happens whan an + * As an example of how this works, let's walk through what happens when an * element is added to the DOM. The [CssAnimate] implementation will add the * `.ng-enter` class to new DOM elements when they are inserted into the DOM * by a directive and will read the computed style. If there is a @@ -35,7 +34,7 @@ * precomputed duration) the `.ng-enter` and `.ng-enter-active` classes * will be removed from the DOM element. * - * When removing elements from the DOM, a simliar pattern is followed. The + * When removing elements from the DOM, a similar pattern is followed. The * `.ng-leave` class will be added to an element, the transition and / or * keyframe animation duration will be computed, and if it is non-zero the * animation will be run by adding the `.ng-leave-active` class. When @@ -58,7 +57,7 @@ * Fade out example: * * HTML: - *
+ *
* Goodbye world! *
* @@ -71,8 +70,8 @@ * opacity: 0; * } * - * This will perform a fade out animation on the 'goodby' div when the - * `ctrl.visible` property goes from `true` to `false`. + * This will perform a fade out animation on the 'goodbye' div when the + * `visible` property goes from `true` to `false`. * * The [CssAnimate] will also do optimizations on running animations by * preventing child DOM animations with the [AnimationOptimizer]. This @@ -129,11 +128,11 @@ final Logger _logger = new Logger('ng.animate'); * of view construction, and some of the native directives to allow you to add * and define css transition and keyframe animations for the styles of your * elements. - * + * * Example html: * *
...
- * + * * Example css defining an opacity transition over .5 seconds using the * `.ng-enter` and `.ng-leave` css classes: * @@ -144,7 +143,7 @@ final Logger _logger = new Logger('ng.animate'); * .my-div.ng-enter-active { * opacity: 1; * } - * + * * .my-div.ng-leave { * transition: all 500ms; * opacity: 1; diff --git a/lib/core_dom/event_handler.dart b/lib/core_dom/event_handler.dart index 1a0f5d9b5..30b5ee432 100644 --- a/lib/core_dom/event_handler.dart +++ b/lib/core_dom/event_handler.dart @@ -4,7 +4,7 @@ typedef void EventFunction(event); /** * [EventHandler] is responsible for handling events bound using on-* syntax - * (i.e. `on-click="ctrl.doSomething();"`). The root of the application has an + * (i.e. `on-click="doSomething();"`). The root of the application has an * EventHandler attached as does every [Component]. * * Events bound within [Component] are handled by EventHandler attached to @@ -16,12 +16,14 @@ typedef void EventFunction(event); * Example: * *
- * ; + * ; *
* - * @Component(selector: '[foo]', publishAs: ctrl) + * @Component(selector: '[foo]') * class FooController { - * say(String something) => print(something); + * void say(String something) { + * print(something); + * } * } * * When button is clicked, "Hello" will be printed in the console. diff --git a/lib/core_dom/transcluding_component_factory.dart b/lib/core_dom/transcluding_component_factory.dart index 008286c34..585f76044 100644 --- a/lib/core_dom/transcluding_component_factory.dart +++ b/lib/core_dom/transcluding_component_factory.dart @@ -1,7 +1,6 @@ part of angular.core.dom_internal; -@Decorator( - selector: 'content') +@Decorator(selector: 'content') class Content implements AttachAware, DetachAware { final ContentPort _port; final dom.Element _element; @@ -12,7 +11,7 @@ class Content implements AttachAware, DetachAware { if (_port == null) return; _beginComment = _port.content(_element); } - + void detach() { if (_port == null) return; _port.detachContent(_beginComment); @@ -21,16 +20,16 @@ class Content implements AttachAware, DetachAware { class ContentPort { dom.Element _element; - var _childNodes = []; + final _childNodes = []; ContentPort(this._element); void pullNodes() { _childNodes.addAll(_element.nodes); - _element.nodes = []; + _element.nodes.clear(); } - content(dom.Element elt) { + dom.Comment content(dom.Element elt) { var hash = elt.hashCode; var beginComment = new dom.Comment("content $hash"); @@ -38,7 +37,7 @@ class ContentPort { elt.parent.insertBefore(beginComment, elt); elt.parent.insertAllBefore(_childNodes, elt); elt.parent.insertBefore(new dom.Comment("end-content $hash"), elt); - _childNodes = []; + _childNodes.clear(); } elt.remove(); return beginComment; diff --git a/lib/directive/module.dart b/lib/directive/module.dart index 37c01c3a6..aea95b368 100644 --- a/lib/directive/module.dart +++ b/lib/directive/module.dart @@ -12,7 +12,7 @@ * * For example: * - * this text is conditionally visible + * this text is conditionally visible * */ library angular.directive; diff --git a/lib/directive/ng_if.dart b/lib/directive/ng_if.dart index 562bfa181..adcfc4481 100644 --- a/lib/directive/ng_if.dart +++ b/lib/directive/ng_if.dart @@ -1,7 +1,7 @@ part of angular.directive; /** - * Base class for NgIf and NgUnless. + * Base class for [NgIf] and [NgUnless]. */ abstract class _NgUnlessIfAttrDirectiveBase { final BoundViewFactory _boundViewFactory; From 722228bd4f04d84108e26d2dd40c02d4a41f5135 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 24 Apr 2014 14:30:53 +0200 Subject: [PATCH 03/29] minors --- lib/core/annotation_src.dart | 19 ------ test/core/annotation_src_spec.dart | 2 - test/core/core_directive_spec.dart | 10 ++- test/core_dom/compiler_spec.dart | 62 +++++++------------ test/core_dom/event_handler_spec.dart | 14 ++--- test/directive/ng_model_spec.dart | 30 ++++----- test/io/expression_extractor_spec.dart | 12 ++-- test/io/test_files/main.dart | 2 +- test/io/test_files/main.html | 21 +++---- test/tools/html_extractor_spec.dart | 24 +++---- .../tools/source_metadata_extractor_spec.dart | 4 +- 11 files changed, 75 insertions(+), 125 deletions(-) diff --git a/lib/core/annotation_src.dart b/lib/core/annotation_src.dart index 643339ca9..926e5fa15 100644 --- a/lib/core/annotation_src.dart +++ b/lib/core/annotation_src.dart @@ -300,14 +300,6 @@ class Component extends Directive { } final bool _resetStyleInheritance; - /** - * An expression under which the component's controller instance will be - * published into. This allows the expressions in the template to be referring - * to controller instance and its properties. - */ - @deprecated - final String publishAs; - /** * If set to true, this component will always use shadow DOM. * If set to false, this component will never use shadow DOM. @@ -321,7 +313,6 @@ class Component extends Directive { cssUrl, applyAuthorStyles, resetStyleInheritance, - this.publishAs, module, map, selector, @@ -351,7 +342,6 @@ class Component extends Directive { cssUrl: cssUrls, applyAuthorStyles: applyAuthorStyles, resetStyleInheritance: resetStyleInheritance, - publishAs: publishAs, map: newMap, module: module, selector: selector, @@ -420,16 +410,8 @@ class Decorator extends Directive { */ @deprecated class Controller extends Decorator { - /** - * An expression under which the controller instance will be published into. - * This allows the expressions in the template to be referring to controller - * instance and its properties. - */ - final String publishAs; - const Controller({ children: Directive.COMPILE_CHILDREN, - this.publishAs, map, module, selector, @@ -448,7 +430,6 @@ class Controller extends Decorator { Directive _cloneWithNewMap(newMap) => new Controller( children: children, - publishAs: publishAs, module: module, map: newMap, selector: selector, diff --git a/test/core/annotation_src_spec.dart b/test/core/annotation_src_spec.dart index 2bfeafce3..78a27f061 100644 --- a/test/core/annotation_src_spec.dart +++ b/test/core/annotation_src_spec.dart @@ -39,7 +39,6 @@ void main() => describe('annotations', () { cssUrl: [''], applyAuthorStyles: true, resetStyleInheritance: true, - publishAs: '', module: (){}, map: {}, selector: '', @@ -80,7 +79,6 @@ void main() => describe('annotations', () { describe('controller', () { it('should set all fields on clone when all the fields are set', () { var controller = new Controller( - publishAs: '', children: 'xxx', map: {}, selector: '', diff --git a/test/core/core_directive_spec.dart b/test/core/core_directive_spec.dart index ab4cd3149..c082e868b 100644 --- a/test/core/core_directive_spec.dart +++ b/test/core/core_directive_spec.dart @@ -23,7 +23,6 @@ void main() { expect(annotation.template).toEqual('template'); expect(annotation.templateUrl).toEqual('templateUrl'); expect(annotation.cssUrls).toEqual(['cssUrls']); - expect(annotation.publishAs).toEqual('ctrl'); expect(annotation.map).toEqual({ 'foo': '=>foo', 'attr': '@attr', @@ -104,15 +103,14 @@ class NullParser implements Parser { template: 'template', templateUrl: 'templateUrl', cssUrl: const ['cssUrls'], - publishAs: 'ctrl', module: AnnotatedIoComponent.module, visibility: Directive.LOCAL_VISIBILITY, exportExpressions: const ['exportExpressions'], - map: const { - 'foo': '=>foo' - }) + map: const {'foo': '=>foo'}) class AnnotatedIoComponent { - static module() => new Module()..bind(String, toFactory: (i) => i.get(AnnotatedIoComponent), + static module() => new Module()..bind( + String, + toFactory: (i) => i.get(AnnotatedIoComponent), visibility: Directive.LOCAL_VISIBILITY); AnnotatedIoComponent(Scope scope) { diff --git a/test/core_dom/compiler_spec.dart b/test/core_dom/compiler_spec.dart index 750ed46c5..460a28670 100644 --- a/test/core_dom/compiler_spec.dart +++ b/test/core_dom/compiler_spec.dart @@ -758,18 +758,12 @@ void main() { } -@Controller( - selector: '[my-parent-controller]', - publishAs: 'my_parent') +@Controller(selector: '[my-parent-controller]') class MyParentController { - data() { - return "my data"; - } + String data() => "my data"; } -@Controller( - selector: '[my-child-controller]', - publishAs: 'my_child') +@Controller(selector: '[my-child-controller]') class MyChildController {} @Component( @@ -882,8 +876,7 @@ class SimpleComponent { @Component( selector: 'shadowy', template: r'With shadow DOM', - useShadowDom: true -) + useShadowDom: true) class ShadowyComponent { ShadowyComponent(Logger log) { log('shadowy'); @@ -893,8 +886,7 @@ class ShadowyComponent { @Component( selector: 'shadowless', template: r'Without shadow DOM', - useShadowDom: false -) + useShadowDom: false) class ShadowlessComponent { ShadowlessComponent(Logger log) { log('shadowless'); @@ -903,13 +895,13 @@ class ShadowlessComponent { @Component( selector: 'sometimes', - template: r'
', - publishAs: 'ctrl') + template: r'
') class SometimesComponent { @NgTwoWay('sometimes') var sometimes; } +// todo(vicb) @Component( selector: 'io', template: r'', @@ -920,8 +912,7 @@ class SometimesComponent { }) class IoComponent { Scope scope; - IoComponent(Scope scope) { - this.scope = scope; + IoComponent(this.scope) { scope.rootScope.context['ioComponent'] = this; scope.context['expr'] = 'initialExpr'; } @@ -930,7 +921,6 @@ class IoComponent { @Component( selector: 'io-controller', template: r'', - publishAs: 'ctrl', map: const { 'attr': '@attr', 'expr': '<=>expr', @@ -945,8 +935,7 @@ class IoControllerComponent { var exprOnce; var onDone; var onOptional; - IoControllerComponent(Scope scope) { - this.scope = scope; + IoControllerComponent(this.scope) { scope.rootScope.context['ioComponent'] = this; } } @@ -1010,15 +999,12 @@ class ParentExpressionComponent { @Component( selector: 'publish-me', - template: r'{{ctrlName.value}}', - publishAs: 'ctrlName') + template: r'{{ctrlName.value}}') class PublishMeComponent { String value = 'WORKED'; } -@Controller ( - selector: '[publish-me]', - publishAs: 'ctrlName') +@Controller (selector: '[publish-me]') class PublishMeDirective { String value = 'WORKED'; } @@ -1026,8 +1012,7 @@ class PublishMeDirective { @Component( selector: 'log', - template: r'', - publishAs: 'ctrlName') + template: r'') class LogComponent { LogComponent(Scope scope, Logger logger) { logger(scope); @@ -1058,17 +1043,17 @@ class AttachDetachComponent implements AttachAware, DetachAware, ShadowRootAware templateLoader.template.then((_) => logger('templateLoaded')); } - attach() => logger('attach:@$attrValue; =>$exprValue; =>!$onceValue'); - detach() => logger('detach'); - onShadowRoot(shadowRoot) { + void attach() => logger('attach:@$attrValue; =>$exprValue; =>!$onceValue'); + + void detach() => logger('detach'); + + void onShadowRoot(shadowRoot) { scope.rootScope.context['shadowRoot'] = shadowRoot; logger(shadowRoot); } } -@Controller( - selector: '[my-controller]', - publishAs: 'myCtrl') +@Controller(selector: '[my-controller]') class MyController { MyController(Scope scope) { scope.context['name'] = 'MyController'; @@ -1083,15 +1068,12 @@ class InvalidSelector {} @Formatter(name:'hello') class SayHelloFormatter { - call(String str) { - return 'Hello, $str!'; - } + String call(String str) => 'Hello, $str!'; } @Component( selector: 'expr-attr-component', template: r'', - publishAs: 'ctrl', map: const { 'expr': '<=>expr', 'one-way': '=>oneWay', @@ -1115,8 +1097,8 @@ class SimpleAttachComponent implements AttachAware, ShadowRootAware { SimpleAttachComponent(this.logger) { logger('SimpleAttachComponent'); } - attach() => logger('attach'); - onShadowRoot(_) => logger('onShadowRoot'); + void attach() => logger('attach'); + void onShadowRoot(_) => logger('onShadowRoot'); } @Component( @@ -1124,7 +1106,7 @@ class SimpleAttachComponent implements AttachAware, ShadowRootAware { templateUrl: 'foo.html') class LogElementComponent{ LogElementComponent(Logger logger, Element element, Node node, - ShadowRoot shadowRoot) { + ShadowRoot shadowRoot) { logger(element); logger(node); logger(shadowRoot); diff --git a/test/core_dom/event_handler_spec.dart b/test/core_dom/event_handler_spec.dart index 43b3b9149..0ea1a9e2e 100644 --- a/test/core_dom/event_handler_spec.dart +++ b/test/core_dom/event_handler_spec.dart @@ -2,7 +2,7 @@ library event_handler_spec; import '../_specs.dart'; -@Controller(selector: '[foo]', publishAs: 'ctrl') +@Controller(selector: '[foo]') class FooController { var description = "desc"; var invoked = false; @@ -11,14 +11,14 @@ class FooController { @Component(selector: 'bar', template: '''
- +
- ''', - publishAs: 'ctrl') + ''') class BarComponent { var invoked = false; BarComponent(RootScope scope) { + // todo(vicb) scope.context['ctrl'] = this; } } @@ -58,7 +58,7 @@ main() { it('shoud register and handle event with long name', inject((TestBed _) { var e = compile(_, '''
-
+
'''); _.triggerEvent(e.querySelector('[on-my-new-event]'), 'myNewEvent'); @@ -69,7 +69,7 @@ main() { it('shoud have model updates applied correctly', inject((TestBed _) { var e = compile(_, '''
-
{{ctrl.description}}
+
{{description}}
'''); var el = document.querySelector('[on-abc]'); el.dispatchEvent(new Event('abc')); @@ -93,7 +93,7 @@ main() { var e = compile(_, '''
-
+
'''); diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart index 63bc86b5c..2d03381ff 100644 --- a/test/directive/ng_model_spec.dart +++ b/test/directive/ng_model_spec.dart @@ -1353,7 +1353,7 @@ void main() { describe('error messages', () { it('should produce a useful error for bad ng-model expressions', () { expect(async(() { - _.compile('
value; - parse(value) { + String format(value) => value; + String parse(value) { return value != null ? value.toLowerCase() : null; } } class UppercaseValueFormatter implements NgModelConverter { final name = 'uppercase'; - parse(value) => value; - format(value) { + String parse(value) => value; + String format(value) { return value != null ? value.toUpperCase() : null; } } class FailedValueParser implements NgModelConverter { final name = 'failed'; - format(value) => value; - parse(value) { + String format(value) => value; + String parse(value) { throw new Exception(); } } class VowelValueParser implements NgModelConverter { final name = 'vowel'; - parse(value) => value; - format(value) { + String parse(value) => value; + String format(value) { if(value != null) { - var exp = new RegExp("[^aeiouAEIOU]"); + var exp = new RegExp("[^aeiou]", caseSensitive: false); value = value.replaceAll(exp, ""); } return value; } } -@Decorator( - selector: '[custom-input-validation]') +@Decorator(selector: '[custom-input-validation]') class MyCustomInputValidator extends NgValidator { MyCustomInputValidator(NgModel ngModel) { ngModel.addValidator(this); @@ -1653,8 +1650,7 @@ class MyCustomInputValidator extends NgValidator { } } -@Decorator( - selector: '[counting-validator]') +@Decorator(selector: '[counting-validator]') class CountingValidator extends NgValidator { final String name = 'counting'; diff --git a/test/io/expression_extractor_spec.dart b/test/io/expression_extractor_spec.dart index cf04340a3..8bb4fa0a7 100644 --- a/test/io/expression_extractor_spec.dart +++ b/test/io/expression_extractor_spec.dart @@ -35,19 +35,19 @@ void main() { var expressions = _extractExpressions('test/io/test_files/main.dart'); expect(expressions, unorderedEquals([ - 'ctrl.expr', - 'ctrl.anotherExpression', - 'ctrl.callback', - 'ctrl.twoWayStuff', + 'expr', + 'anotherExpression', + 'callback', + 'twoWayStuff', 'attr', 'expr', 'anotherExpression', 'callback', 'twoWayStuff', 'exported + expression', - 'ctrl.inline.template.expression', + 'inline.template.expression', 'ngIfCondition', - 'ctrl.if' + 'if' ])); }); diff --git a/test/io/test_files/main.dart b/test/io/test_files/main.dart index cd263cdfd..094684265 100644 --- a/test/io/test_files/main.dart +++ b/test/io/test_files/main.dart @@ -16,7 +16,7 @@ class NgIfDirective { 'attr': '@attr', 'expr': '=>expr' }, - template: '
{{ctrl.inline.template.expression}}
', + template: '
{{inline.template.expression}}
', exportExpressionAttrs: const ['exported-attr'], exportExpressions: const ['exported + expression']) class MyComponent { diff --git a/test/io/test_files/main.html b/test/io/test_files/main.html index 95ecc8ad0..41b1ff188 100644 --- a/test/io/test_files/main.html +++ b/test/io/test_files/main.html @@ -1,16 +1,15 @@
- + + attr="attr2" expr="expr2" + another-expression="anotherExpression2" + callback="callback2" + two-way-stuff="twoWayStuff2"> -
-
+
\ No newline at end of file diff --git a/test/tools/html_extractor_spec.dart b/test/tools/html_extractor_spec.dart index 976e19442..7eefd6f6c 100644 --- a/test/tools/html_extractor_spec.dart +++ b/test/tools/html_extractor_spec.dart @@ -13,40 +13,40 @@ void main() { it('should extract text mustache expressions', () { var ioService = new MockIoService({ 'foo.html': r''' -
foo {{ctrl.bar}} baz {{aux}}
+
foo {{bar}} baz {{aux}}
''' }); var extractor = new HtmlExpressionExtractor([]); extractor.crawl('/', ioService); expect(extractor.expressions.toList()..sort(), - equals(['aux', 'ctrl.bar'])); + equals(['aux', 'bar'])); }); it('should extract attribute mustache expressions', () { var ioService = new MockIoService({ 'foo.html': r''' -
+
''' }); var extractor = new HtmlExpressionExtractor([]); extractor.crawl('/', ioService); expect(extractor.expressions.toList()..sort(), - equals(['aux', 'ctrl.bar'])); + equals(['aux', 'bar'])); }); it('should extract ng-repeat expressions', () { var ioService = new MockIoService({ 'foo.html': r''' -
+
''' }); var extractor = new HtmlExpressionExtractor([]); extractor.crawl('/', ioService); expect(extractor.expressions.toList()..sort(), - equals(['ctrl.bar'])); + equals(['bar'])); }); it('should extract expressions provided in the directive info', () { @@ -62,9 +62,7 @@ void main() { it('should extract expressions from expression attributes', () { var ioService = new MockIoService({ - 'foo.html': r''' - - ''' + 'foo.html': r'' }); var extractor = new HtmlExpressionExtractor([ @@ -72,14 +70,12 @@ void main() { ]); extractor.crawl('/', ioService); expect(extractor.expressions.toList()..sort(), - equals(['ctrl.baz'])); + equals(['baz'])); }); it('should ignore ng-repeat while extracting attribute expressions', () { var ioService = new MockIoService({ - 'foo.html': r''' -
- ''' + 'foo.html': r'
' }); var extractor = new HtmlExpressionExtractor([ @@ -88,7 +84,7 @@ void main() { extractor.crawl('/', ioService); // Basically we don't want to extract "foo in ctrl.bar". expect(extractor.expressions.toList()..sort(), - equals(['ctrl.bar'])); + equals(['bar'])); }); }); } diff --git a/test/tools/source_metadata_extractor_spec.dart b/test/tools/source_metadata_extractor_spec.dart index 4a4c6c5e8..2f63c84fb 100644 --- a/test/tools/source_metadata_extractor_spec.dart +++ b/test/tools/source_metadata_extractor_spec.dart @@ -105,11 +105,11 @@ void main() { var info = extractDirectiveInfo([ new DirectiveMetadata('MyFooAttrDirective', DIRECTIVE, '[blah][foo]', { '.': '=>fooExpr' - }, null, ['ctrl.baz']) + }, null, ['baz']) ]); expect(flattenList(info, (DirectiveInfo i) => i.expressions), - equals(['fooExpr', 'ctrl.baz'])); + equals(['fooExpr', 'baz'])); }); }); From 5e2b8b37cd54eefe595c616643bdabf0e3a39fc7 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 24 Apr 2014 16:41:30 +0200 Subject: [PATCH 04/29] changes #1 --- .../dirty_checking_change_detector.dart | 16 +++- lib/change_detection/prototype_map.dart | 46 +++++------ lib/change_detection/watch_group.dart | 6 +- lib/core/module.dart | 2 +- lib/core/scope.dart | 46 +++++++---- lib/core_dom/common.dart | 3 +- lib/core_dom/element_binder.dart | 23 +++--- lib/core_dom/module_internal.dart | 5 +- lib/core_dom/mustache.dart | 3 + .../shadow_dom_component_factory.dart | 14 ++-- .../transcluding_component_factory.dart | 2 +- lib/directive/ng_if.dart | 16 +--- lib/directive/ng_include.dart | 42 ++++------ lib/directive/ng_repeat.dart | 33 +++----- lib/directive/ng_switch.dart | 80 ++++++++----------- lib/routing/ng_view.dart | 13 ++- 16 files changed, 168 insertions(+), 182 deletions(-) diff --git a/lib/change_detection/dirty_checking_change_detector.dart b/lib/change_detection/dirty_checking_change_detector.dart index ab940ac07..2fd5d0a6d 100644 --- a/lib/change_detection/dirty_checking_change_detector.dart +++ b/lib/change_detection/dirty_checking_change_detector.dart @@ -2,6 +2,7 @@ library dirty_checking_change_detector; import 'dart:collection'; import 'package:angular/change_detection/change_detection.dart'; +import 'package:angular/change_detection/watch_group.dart'; /** * [DirtyCheckingChangeDetector] determines which object properties have changed @@ -369,7 +370,7 @@ class _ChangeIterator implements Iterator>{ * removing efficient. [DirtyCheckingRecord] also has a [nextChange] field which * creates a single linked list of all of the changes for efficient traversal. */ -class DirtyCheckingRecord implements Record, WatchRecord { +class DirtyCheckingRecord implements WatchRecord { static const List _MODE_NAMES = const ['MARKER', 'IDENT', 'GETTER', 'MAP[]', 'ITERABLE', 'MAP']; static const int _MODE_MARKER_ = 0; @@ -456,6 +457,19 @@ class DirtyCheckingRecord implements Record, WatchRecord { return; } + while (obj is LocalContext) { + var ctx = obj as LocalContext; + if (ctx.hasProperty(field)) { + _object = obj; + _mode = _MODE_MAP_FIELD_; + _getter = null; + return; + } + obj = ctx.parent; + } + + if (obj == null) throw "$field property does not exist on $_object"; + if (obj is Map) { _mode = _MODE_MAP_FIELD_; _getter = null; diff --git a/lib/change_detection/prototype_map.dart b/lib/change_detection/prototype_map.dart index 130444184..e665d0f55 100644 --- a/lib/change_detection/prototype_map.dart +++ b/lib/change_detection/prototype_map.dart @@ -1,37 +1,27 @@ part of angular.watch_group; -class PrototypeMap implements Map { - final Map prototype; - final Map self = new Map(); +// todo(vicb) rename to ContextLocals + rename the file +class LocalContext { + // todo(vicb) _parentContext + final Object parent; + final Map _locals = {}; - PrototypeMap(this.prototype); - - void operator []=(name, value) { - self[name] = value; + LocalContext(this.parent, [Map locals = null]) { + if (locals != null) _locals.addAll(locals); + _locals[r'$parent'] = parent; } - V operator [](name) => self.containsKey(name) ? self[name] : prototype[name]; - bool get isEmpty => self.isEmpty && prototype.isEmpty; - bool get isNotEmpty => self.isNotEmpty || prototype.isNotEmpty; - // todo(vbe) include prototype keys ? - Iterable get keys => self.keys; - // todo(vbe) include prototype values ? - Iterable get values => self.values; - int get length => self.length; + static LocalContext wrapper(context, Map locals) => + new LocalContext(context, locals); + + bool hasProperty(String prop) => _locals.containsKey(prop); - void forEach(fn) { - // todo(vbe) include prototype ? - self.forEach(fn); + void operator[]=(String prop, value) { + _locals[prop] = value; } - V remove(key) => self.remove(key); - clear() => self.clear; - // todo(vbe) include prototype ? - bool containsKey(key) => self.containsKey(key); - // todo(vbe) include prototype ? - bool containsValue(key) => self.containsValue(key); - void addAll(map) { - self.addAll(map); + + dynamic operator[](String prop) { + assert(hasProperty(prop)); + return _locals[prop]; } - // todo(vbe) include prototype ? - V putIfAbsent(key, fn) => self.putIfAbsent(key, fn); } diff --git a/lib/change_detection/watch_group.dart b/lib/change_detection/watch_group.dart index b0dbd05f0..b7eadcaa8 100644 --- a/lib/change_detection/watch_group.dart +++ b/lib/change_detection/watch_group.dart @@ -15,8 +15,10 @@ part 'prototype_map.dart'; * * [value]: The current value of the watched expression. * * [previousValue]: The previous value of the watched expression. * - * If the expression is watching a collection (a list or a map), then [value] is wrapped in - * a [CollectionChangeItem] that lists all the changes. + * Notes: + * + * * [value] is a [CollectionChangeRecord] when a Collection is being watched + * * [value] is a [MapChangeRecord] when a [Map] is being watched */ typedef void ReactionFn(value, previousValue); typedef void ChangeLog(String expression, current, previous); diff --git a/lib/core/module.dart b/lib/core/module.dart index 57b7b2970..ff3ec5763 100644 --- a/lib/core/module.dart +++ b/lib/core/module.dart @@ -63,8 +63,8 @@ export "package:angular/core/module_internal.dart" show ExceptionHandler, Interpolate, VmTurnZone, - PrototypeMap, RootScope, + LocalContext, Scope, ScopeDigestTTL, ScopeEvent, diff --git a/lib/core/scope.dart b/lib/core/scope.dart index 6f3cef32b..f81e392d0 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -138,7 +138,16 @@ class Scope { /** * The default execution context for [watch]es [observe]ers, and [eval]uation. */ - final context; + // todo(vicb) was final + var _context; + + get context => _context; + set context(ctx) { + + print("scope: setting context to $ctx"); + _context = ctx; + + } /** * The [RootScope] of the application. @@ -184,9 +193,12 @@ class Scope { /// Do not use. Exposes internal state for testing. bool get hasOwnStreams => _streams != null && _streams._scope == this; - Scope(Object this.context, this.rootScope, this._parentScope, + // todo(vicb) this.context + Scope(Object _context, this.rootScope, this._parentScope, this._readWriteGroup, this._readOnlyGroup, this.id, - this._stats); + this._stats) { + context = _context; + } /** * Use [watch] to set up change detection on an expression. @@ -206,7 +218,7 @@ class Scope { * by reference. When watching a collection, the reaction function receives a * [CollectionChangeItem] that lists all the changes. */ - Watch watch(String expression, ReactionFn reactionFn, {context, + Watch watch(String expression, ReactionFn reactionFn, {context, FormatterMap formatters, bool canChangeModel: true, bool collection: false}) { assert(isAttached); assert(expression is String); @@ -246,8 +258,8 @@ class Scope { expression is String || expression is Function); if (expression is String && expression.isNotEmpty) { - var obj = locals == null ? context : new ScopeLocals(context, locals); - return rootScope._parser(expression).eval(obj); + var ctx = locals == null ? context : new LocalContext(context, locals); + return rootScope._parser(expression).eval(ctx); } assert(locals == null); @@ -323,7 +335,7 @@ class Scope { _parentScope = null; } - _assertInternalStateConsistency() { + void _assertInternalStateConsistency() { assert((() { rootScope._verifyStreams(null, '', []); return true; @@ -360,7 +372,7 @@ class Scope { } } -_mapEqual(Map a, Map b) => a.length == b.length && +bool _mapEqual(Map a, Map b) => a.length == b.length && a.keys.every((k) => b.containsKey(k) && a[k] == b[k]); /** @@ -401,7 +413,7 @@ class ScopeStats { processStopwatch.elapsedMicroseconds; } - _stopwatchReset() { + void _stopwatchReset() { fieldStopwatch.reset(); evalStopwatch.reset(); processStopwatch.reset(); @@ -466,9 +478,9 @@ class ScopeStatsEmitter { static pad(String str, int size) => _PAD_.substring(0, max(size - str.length, 0)) + str; - _ms(num value) => '${pad(_nfDec.format(value), 9)} ms'; - _us(num value) => _ms(value / 1000); - _tally(num value) => '${pad(_nfInt.format(value), 6)}'; + String _ms(num value) => '${pad(_nfDec.format(value), 9)} ms'; + String _us(num value) => _ms(value / 1000); + String _tally(num value) => '${pad(_nfInt.format(value), 6)}'; /** * Emit a message based on the phase and state of stopwatches. @@ -492,9 +504,8 @@ class ScopeStatsEmitter { return (prefix == '1' ? _HEADER_ : '') + ' #$prefix:'; } - String _stat(AvgStopwatch s) { - return '${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)'; - } + String _stat(AvgStopwatch s) => + '${_tally(s.count)} / ${_us(s.elapsedMicroseconds)} @(${_tally(s.ratePerMs)} #/ms)'; } /** @@ -505,6 +516,7 @@ class ScopeStatsConfig { var emit = false; ScopeStatsConfig(); + ScopeStatsConfig.enabled() { emit = true; } @@ -570,8 +582,8 @@ class RootScope extends Scope { * followed by change detection * on non-DOM listeners. Any changes detected are process using the reaction function. The digest * phase is repeated as long as at least one change has been detected. By default, after 5 - * iterations the model is considered unstable and angular exists with an exception. (See - * ScopeDigestTTL) + * iterations the model is considered unstable and angular exits with an exception. (See + * [ScopeDigestTTL]) * * ##flush * diff --git a/lib/core_dom/common.dart b/lib/core_dom/common.dart index a60a050ee..c99f2da53 100644 --- a/lib/core_dom/common.dart +++ b/lib/core_dom/common.dart @@ -39,7 +39,8 @@ Injector forceNewDirectivesAndFormatters(Injector injector, List modules modules.add(new Module() ..bind(Scope, toFactory: (i) { var scope = i.parent.get(Scope); - return scope.createChild(new PrototypeMap(scope.context)); + //todo(vicb) + return scope.createChild(scope.context); })); return injector.createChild(modules, diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index bc562c675..1ed2cb20f 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -200,13 +200,16 @@ class ElementBinder { probe.directives.add(controller); assert((linkMapTimer = _perf.startTimer('ng.view.link.map', ref.type)) != false); + if (ref.annotation is Controller) { - scope.context[(ref.annotation as Controller).publishAs] = controller; + // todo(vicb) + print("_link context = $controller"); + scope.context = controller; } - var tasks = new _TaskList(controller is AttachAware ? () { - if (scope.isAttached) controller.attach(); - } : null); + var tasks = new _TaskList(controller is AttachAware ? + () {if (scope.isAttached) controller.attach();} : + null); if (ref.mappings.isNotEmpty) { if (nodeAttrs == null) nodeAttrs = new _AnchorAttrs(ref); @@ -302,16 +305,16 @@ class ElementBinder { directiveRefs.forEach((DirectiveRef ref) { Directive annotation = ref.annotation; - var visibility = ref.annotation.visibility; - if (ref.annotation is Controller) { - scope = scope.createChild(new PrototypeMap(scope.context)); + if (annotation is Controller) { + //todo(vicb) + scope = scope.createChild(scope.context); nodeModule.bind(Scope, toValue: scope); } _createDirectiveFactories(ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs, - visibility); - if (ref.annotation.module != null) { - nodeModule.install(ref.annotation.module()); + annotation.visibility); + if (annotation.module != null) { + nodeModule.install(annotation.module()); } }); diff --git a/lib/core_dom/module_internal.dart b/lib/core_dom/module_internal.dart index decce9591..491e62b2c 100644 --- a/lib/core_dom/module_internal.dart +++ b/lib/core_dom/module_internal.dart @@ -13,7 +13,8 @@ import 'package:angular/core/module_internal.dart'; import 'package:angular/core/parser/parser.dart'; import 'package:angular/core_dom/dom_util.dart' as util; -import 'package:angular/change_detection/watch_group.dart' show Watch, PrototypeMap; +// todo vicb +import 'package:angular/change_detection/watch_group.dart' show Watch, LocalContext; import 'package:angular/core/registry.dart'; import 'package:angular/directive/module.dart' show NgBaseCss; @@ -62,7 +63,7 @@ class CoreDomModule extends Module { bind(TranscludingComponentFactory); bind(Content); bind(ContentPort, toValue: null); - + bind(Http); bind(UrlRewriter); bind(HttpBackend); diff --git a/lib/core_dom/mustache.dart b/lib/core_dom/mustache.dart index 1cc242c15..616c67df3 100644 --- a/lib/core_dom/mustache.dart +++ b/lib/core_dom/mustache.dart @@ -12,6 +12,8 @@ class TextMustache { FormatterMap formatters) { String expression = interpolate(template); + print('Mustache: watching $expression'); + scope.watch(expression, _updateMarkup, canChangeModel: false, @@ -19,6 +21,7 @@ class TextMustache { } void _updateMarkup(text, previousText) { + print('Mustache: changed $previousText -> $text'); _element.text = text; } } diff --git a/lib/core_dom/shadow_dom_component_factory.dart b/lib/core_dom/shadow_dom_component_factory.dart index 5782f96d1..0c128893a 100644 --- a/lib/core_dom/shadow_dom_component_factory.dart +++ b/lib/core_dom/shadow_dom_component_factory.dart @@ -35,19 +35,19 @@ class ShadowDomComponentFactory implements ComponentFactory { FactoryFn call(dom.Node node, DirectiveRef ref) { return (Injector injector) { var component = ref.annotation as Component; - Scope scope = injector.get(Scope); - ViewCache viewCache = injector.get(ViewCache); - Http http = injector.get(Http); - TemplateCache templateCache = injector.get(TemplateCache); - DirectiveMap directives = injector.get(DirectiveMap); - NgBaseCss baseCss = injector.get(NgBaseCss); + final scope = injector.get(Scope); + final viewCache = injector.get(ViewCache); + final http = injector.get(Http); + final templateCache = injector.get(TemplateCache); + final directives = injector.get(DirectiveMap); + final baseCss = injector.get(NgBaseCss); // This is a bit of a hack since we are returning different type then we are. var componentFactory = new _ComponentFactory(node, ref.type, component, injector.get(dom.NodeTreeSanitizer), _expando, baseCss, _styleElementCache); var controller = componentFactory.call(injector, scope, viewCache, http, templateCache, directives); - componentFactory.shadowScope.context[component.publishAs] = controller; + componentFactory.shadowScope.context = controller; return controller; }; } diff --git a/lib/core_dom/transcluding_component_factory.dart b/lib/core_dom/transcluding_component_factory.dart index 585f76044..f298e4188 100644 --- a/lib/core_dom/transcluding_component_factory.dart +++ b/lib/core_dom/transcluding_component_factory.dart @@ -114,7 +114,7 @@ class TranscludingComponentFactory implements ComponentFactory { childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME); var controller = childInjector.get(ref.type); - shadowScope.context[component.publishAs] = controller; + shadowScope.context = controller; ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); return controller; }; diff --git a/lib/directive/ng_if.dart b/lib/directive/ng_if.dart index adcfc4481..fd419e09a 100644 --- a/lib/directive/ng_if.dart +++ b/lib/directive/ng_if.dart @@ -10,24 +10,14 @@ abstract class _NgUnlessIfAttrDirectiveBase { View _view; - /** - * The new child scope. This child scope is recreated whenever the `ng-if` - * subtree is inserted into the DOM and destroyed when it's removed from the - * DOM. Refer - * https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-prototypical-Inheritance prototypical inheritance - */ - Scope _childScope; - - _NgUnlessIfAttrDirectiveBase(this._boundViewFactory, this._viewPort, - this._scope); + _NgUnlessIfAttrDirectiveBase(this._boundViewFactory, this._viewPort, this._scope); // Override in subclass. void set condition(value); void _ensureViewExists() { if (_view == null) { - _childScope = _scope.createChild(new PrototypeMap(_scope.context)); - _view = _boundViewFactory(_childScope); + _view = _boundViewFactory(_scope); var view = _view; _scope.rootScope.domWrite(() { _viewPort.insert(view); @@ -41,9 +31,7 @@ abstract class _NgUnlessIfAttrDirectiveBase { _scope.rootScope.domWrite(() { _viewPort.remove(view); }); - _childScope.destroy(); _view = null; - _childScope = null; } } } diff --git a/lib/directive/ng_include.dart b/lib/directive/ng_include.dart index be450524f..981693eb9 100644 --- a/lib/directive/ng_include.dart +++ b/lib/directive/ng_include.dart @@ -19,43 +19,35 @@ part of angular.directive; selector: '[ng-include]', map: const {'ng-include': '@url'}) class NgInclude { - - final dom.Element element; - final Scope scope; - final ViewCache viewCache; - final Injector injector; - final DirectiveMap directives; + final dom.Element _element; + final Scope _scope; + final ViewCache _viewCache; + final Injector _injector; + final DirectiveMap _directives; View _view; - Scope _scope; - NgInclude(this.element, this.scope, this.viewCache, this.injector, this.directives); + NgInclude(this._element, this._scope, this._viewCache, this._injector, this._directives); - _cleanUp() { - if (_view == null) return; + void set url(value) { + _cleanUp(); + if (value != null && value != '') { + _viewCache.fromUrl(value, _directives).then(_updateContent); + } + } + void _cleanUp() { + if (_view == null) return; _view.nodes.forEach((node) => node.remove); - _scope.destroy(); - element.innerHtml = ''; - + _element.innerHtml = ''; _view = null; - _scope = null; } - _updateContent(createView) { + void _updateContent(createView) { // create a new scope _scope = scope.createChild(new PrototypeMap(scope.context)); - _view = createView(injector.createChild([new Module() - ..bind(Scope, toValue: _scope)])); + _view = createView(new Module()..bind(Scope, toValue: _scope)); _view.nodes.forEach((node) => element.append(node)); } - - - set url(value) { - _cleanUp(); - if (value != null && value != '') { - viewCache.fromUrl(value, directives).then(_updateContent); - } - } } diff --git a/lib/directive/ng_repeat.dart b/lib/directive/ng_repeat.dart index 99e7d93e9..fb9dcba24 100644 --- a/lib/directive/ng_repeat.dart +++ b/lib/directive/ng_repeat.dart @@ -112,8 +112,7 @@ class NgRepeat { ..[r'$index'] = index ..[r'$id'] = (obj) => obj; if (_keyIdentifier != null) context[_keyIdentifier] = key; - return relaxFnArgs(trackBy.eval)(new ScopeLocals(_scope.context, - context)); + return relaxFnArgs(trackBy.eval)(new LocalContext(_scope.context, context)); }); } @@ -151,17 +150,12 @@ class NgRepeat { var domIndex; var addRow = (int index, value, View previousView) { - var childContext = _updateContext(new PrototypeMap(_scope.context), index, - length)..[_valueIdentifier] = value; + // todo vicb + var childContext = new LocalContext(_scope.context); + childContext = _updateContext(childContext, index, length, _valueIdentifier); var childScope = _scope.createChild(childContext); var view = _boundViewFactory(childScope); - var nodes = view.nodes; - rows[index] = new _Row(_generateId(index, value, index)) - ..view = view - ..scope = childScope - ..nodes = nodes - ..startNode = nodes.first - ..endNode = nodes.last; + rows[index] = new _Row(_generateId(index, value, index), childScope, view); _viewPort.insert(view, insertAfter: previousView); }; @@ -216,8 +210,7 @@ class NgRepeat { if (changeFn == null) { rows[targetIndex] = _rows[targetIndex]; domIndex--; - // The element has not moved but `$last` and `$middle` might still need - // to be updated + // The element has not moved but `$last` and `$middle` might still need to be updated _updateContext(rows[targetIndex].scope.context, targetIndex, length); } else { changeFn(targetIndex, previousView); @@ -228,9 +221,12 @@ class NgRepeat { _rows = rows; } - PrototypeMap _updateContext(PrototypeMap context, int index, int length) { - var first = (index == 0); - var last = (index == length - 1); + LocalContext _updateContext(LocalContext context, int index, int len, [String valueId = null]) { + var first = index == 0; + var last = index == len - 1; + + if (valueId != null) context[r'_valueIdentifier'] = valueId; + return context ..[r'$index'] = index ..[r'$first'] = first @@ -245,9 +241,6 @@ class _Row { final id; Scope scope; View view; - dom.Element startNode; - dom.Element endNode; - List nodes; - _Row(this.id); + _Row(this.id, this.scope, this.view); } diff --git a/lib/directive/ng_switch.dart b/lib/directive/ng_switch.dart index c9aec1275..cf2781c9e 100644 --- a/lib/directive/ng_switch.dart +++ b/lib/directive/ng_switch.dart @@ -1,19 +1,19 @@ part of angular.directive; /** - * The ngSwitch directive is used to conditionally swap DOM structure on your - * template based on a scope expression. Elements within ngSwitch but without - * ngSwitchWhen or ngSwitchDefault directives will be preserved at the location + * The [ngSwitch] directive is used to conditionally swap DOM structure on your + * template based on a scope expression. Elements within [ngSwitch] but without + * [ngSwitchWhen] or [ngSwitchDefault] directives will be preserved at the location * as specified in the template. * - * The directive itself works similar to ngInclude, however, instead of - * downloading template code (or loading it from the template cache), ngSwitch - * simply choses one of the nested elements and makes it visible based on which + * The directive itself works similar to [ngInclude], however, instead of + * downloading template code (or loading it from the template cache), [ngSwitch] + * simply chooses one of the nested elements and makes it visible based on which * element matches the value obtained from the evaluated expression. In other * words, you define a container element (where you place the directive), place * an expression on the **ng-switch="..." attribute**, define any inner elements * inside of the directive and place a when attribute per element. The when - * attribute is used to inform ngSwitch which element to display when the on + * attribute is used to inform [ngSwitch] which element to display when the on * expression is evaluated. If a matching expression is not found via a when * attribute then an element with the default attribute is displayed. * @@ -57,56 +57,49 @@ part of angular.directive; }, visibility: Directive.DIRECT_CHILDREN_VISIBILITY) class NgSwitch { - Map> cases = new Map>(); - List<_ViewScopePair> currentViews = <_ViewScopePair>[]; + final cases = >{'?': <_Case>[]}; + final currentViews = <_ViewScopePair>[]; Function onChange; final Scope scope; - NgSwitch(this.scope) { - cases['?'] = <_Case>[]; - } + NgSwitch(this.scope); - addCase(String value, ViewPort anchor, BoundViewFactory viewFactory) { - cases.putIfAbsent(value, () => <_Case>[]); - cases[value].add(new _Case(anchor, viewFactory)); + void addCase(String value, ViewPort anchor, BoundViewFactory viewFactory) { + cases.putIfAbsent(value, () => <_Case>[]).add(new _Case(anchor, viewFactory)); } - set value(val) { - currentViews - ..forEach((_ViewScopePair pair) { - pair.port.remove(pair.view); - pair.scope.destroy(); - }) - ..clear(); + void set value(val) { + currentViews..forEach((_ViewScopePair pair) => pair.remove()) + ..clear(); val = '!$val'; (cases.containsKey(val) ? cases[val] : cases['?']) .forEach((_Case caze) { - Scope childScope = scope.createChild(new PrototypeMap(scope.context)); - var view = caze.viewFactory(childScope); - caze.anchor.insert(view); - currentViews.add(new _ViewScopePair(view, caze.anchor, - childScope)); + var view = caze.viewFactory(scope); + caze.port.insert(view); + currentViews.add(new _ViewScopePair(view, caze.port)); }); - if (onChange != null) { - onChange(); - } + + if (onChange != null) onChange(); } } class _ViewScopePair { - final View view; - final ViewPort port; - final Scope scope; + final View _view; + final ViewPort _port; + + _ViewScopePair(this._view, this._port); - _ViewScopePair(this.view, this.port, this.scope); + void remove() { + _port.remove(_view); + } } class _Case { - final ViewPort anchor; + final ViewPort port; final BoundViewFactory viewFactory; - _Case(this.anchor, this.viewFactory); + _Case(this.port, this.viewFactory); } @Decorator( @@ -114,23 +107,20 @@ class _Case { children: Directive.TRANSCLUDE_CHILDREN, map: const {'.': '@value'}) class NgSwitchWhen { - final NgSwitch ngSwitch; - final ViewPort port; - final BoundViewFactory viewFactory; - final Scope scope; + final NgSwitch _ngSwitch; + final ViewPort _port; + final BoundViewFactory _viewFactory; - NgSwitchWhen(this.ngSwitch, this.port, this.viewFactory, this.scope); + NgSwitchWhen(this._ngSwitch, this._port, this._viewFactory); - set value(String value) => ngSwitch.addCase('!$value', port, viewFactory); + void set value(String value) => _ngSwitch.addCase('!$value', _port, _viewFactory); } @Decorator( children: Directive.TRANSCLUDE_CHILDREN, selector: '[ng-switch-default]') class NgSwitchDefault { - - NgSwitchDefault(NgSwitch ngSwitch, ViewPort port, - BoundViewFactory viewFactory, Scope scope) { + NgSwitchDefault(NgSwitch ngSwitch, ViewPort port, BoundViewFactory viewFactory) { ngSwitch.addCase('?', port, viewFactory); } } diff --git a/lib/routing/ng_view.dart b/lib/routing/ng_view.dart index 248927ff7..6a8f63dc4 100644 --- a/lib/routing/ng_view.dart +++ b/lib/routing/ng_view.dart @@ -122,9 +122,8 @@ class NgView implements DetachAware, RouteProvider { viewCache.fromUrl(viewDef.template, newDirectives); viewFuture.then((viewFactory) { _cleanUp(); - _scope = scope.createChild(new PrototypeMap(scope.context)); _view = viewFactory( - viewInjector.createChild([new Module()..bind(Scope, toValue: _scope)])); + viewInjector.createChild([new Module()..bind(Scope, toValue: scope)])); _view.nodes.forEach((elm) => element.append(elm)); }); } @@ -133,10 +132,8 @@ class NgView implements DetachAware, RouteProvider { if (_view == null) return; _view.nodes.forEach((node) => node.remove()); - _scope.destroy(); _view = null; - _scope = null; } Route get route => _viewRoute; @@ -154,7 +151,7 @@ class NgView implements DetachAware, RouteProvider { /** - * Class that can be injected to retrieve information about the current route. + * Inject a [RouteProvider] to retrieve information about the current route. * For example: * * @Component(/* ... */) @@ -173,7 +170,7 @@ class NgView implements DetachAware, RouteProvider { * }); * } * - * detach() { + * void detach() { * // The route handle must be discarded. * route.discard(); * } @@ -183,8 +180,8 @@ class NgView implements DetachAware, RouteProvider { * } * } * - * If user component is used outside of ng-view directive then - * injected [RouteProvider] will be null. + * If user component is used outside of ng-view directive then the injected [RouteProvider] will be + * null. */ abstract class RouteProvider { From 2da2de975708e4048f7e43d5036644df47eb8937 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 09:56:43 +0200 Subject: [PATCH 05/29] fix demos --- example/web/animation/css_demo.dart | 1 - example/web/animation/repeat_demo.dart | 1 - example/web/animation/stress_demo.dart | 1 - example/web/animation/visibility_demo.dart | 1 - 4 files changed, 4 deletions(-) diff --git a/example/web/animation/css_demo.dart b/example/web/animation/css_demo.dart index 4814bdef9..5312556f3 100644 --- a/example/web/animation/css_demo.dart +++ b/example/web/animation/css_demo.dart @@ -22,7 +22,6 @@ part of animation;
''', - publishAs: 'ctrl', applyAuthorStyles: true) class CssDemo { bool stateA = false; diff --git a/example/web/animation/repeat_demo.dart b/example/web/animation/repeat_demo.dart index 262e80cd6..8352fee81 100644 --- a/example/web/animation/repeat_demo.dart +++ b/example/web/animation/repeat_demo.dart @@ -15,7 +15,6 @@ part of animation;
''', - publishAs: 'ctrl', applyAuthorStyles: true) class RepeatDemo { var thing = 0; diff --git a/example/web/animation/stress_demo.dart b/example/web/animation/stress_demo.dart index 850912dd1..19938d5ff 100644 --- a/example/web/animation/stress_demo.dart +++ b/example/web/animation/stress_demo.dart @@ -11,7 +11,6 @@ part of animation;
''', - publishAs: 'ctrl', applyAuthorStyles: true) class StressDemo { bool _visible = true; diff --git a/example/web/animation/visibility_demo.dart b/example/web/animation/visibility_demo.dart index 05dd60ea8..53830f3c0 100644 --- a/example/web/animation/visibility_demo.dart +++ b/example/web/animation/visibility_demo.dart @@ -16,7 +16,6 @@ part of animation;
''', - publishAs: 'ctrl', applyAuthorStyles: true) class VisibilityDemo { bool visible = false; From c05f4d06a54d4265b904fdcc0c1e9e5ca9fa2058 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 10:36:58 +0200 Subject: [PATCH 06/29] update demo --- example/web/todo.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/web/todo.dart b/example/web/todo.dart index d415f25a9..fa4b098fc 100644 --- a/example/web/todo.dart +++ b/example/web/todo.dart @@ -53,8 +53,6 @@ class HttpServer implements Server { } } - -@Controller(selector: '[todo-controller]') class Todo { var items = []; Item newItem; @@ -117,5 +115,7 @@ main() { module.bind(HttpBackend, toImplementation: PlaybackHttpBackend); } - applicationFactory().addModule(module).run(); + applicationFactory() + .addModule(module..type(Object, implementedBy: Todo)) + .run(); } From a3b05b5bbfa246b5b90024c2480d55c78784e841 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 15:31:46 +0200 Subject: [PATCH 07/29] Locals aware eval --- .../dirty_checking_change_detector.dart | 8 ++-- lib/change_detection/prototype_map.dart | 29 ++++++++++-- lib/core/module.dart | 2 +- lib/core/parser/dynamic_parser.dart | 7 --- lib/core/parser/parser.dart | 7 +++ lib/core/registry_dynamic.dart | 46 ++++++++++++++++++- lib/core/scope.dart | 20 ++++++-- lib/core_dom/element_binder.dart | 2 +- lib/core_dom/module_internal.dart | 2 +- lib/directive/ng_repeat.dart | 13 +++--- 10 files changed, 104 insertions(+), 32 deletions(-) diff --git a/lib/change_detection/dirty_checking_change_detector.dart b/lib/change_detection/dirty_checking_change_detector.dart index 2fd5d0a6d..6d37cf0ab 100644 --- a/lib/change_detection/dirty_checking_change_detector.dart +++ b/lib/change_detection/dirty_checking_change_detector.dart @@ -457,19 +457,17 @@ class DirtyCheckingRecord implements WatchRecord { return; } - while (obj is LocalContext) { - var ctx = obj as LocalContext; + if (obj is ContextLocals) { + var ctx = obj as ContextLocals; if (ctx.hasProperty(field)) { _object = obj; _mode = _MODE_MAP_FIELD_; _getter = null; return; } - obj = ctx.parent; + obj = ctx.rootContext; } - if (obj == null) throw "$field property does not exist on $_object"; - if (obj is Map) { _mode = _MODE_MAP_FIELD_; _getter = null; diff --git a/lib/change_detection/prototype_map.dart b/lib/change_detection/prototype_map.dart index e665d0f55..d616ae8b2 100644 --- a/lib/change_detection/prototype_map.dart +++ b/lib/change_detection/prototype_map.dart @@ -1,20 +1,34 @@ part of angular.watch_group; // todo(vicb) rename to ContextLocals + rename the file -class LocalContext { +class ContextLocals { // todo(vicb) _parentContext final Object parent; + Object _rootContext; final Map _locals = {}; - LocalContext(this.parent, [Map locals = null]) { + ContextLocals(this.parent, [Map locals = null]) { + assert(parent != null); if (locals != null) _locals.addAll(locals); _locals[r'$parent'] = parent; } - static LocalContext wrapper(context, Map locals) => - new LocalContext(context, locals); + static ContextLocals wrapper(context, Map locals) => + new ContextLocals(context, locals); - bool hasProperty(String prop) => _locals.containsKey(prop); + dynamic get rootContext { + if (_rootContext == null) { + _rootContext = parent is ContextLocals ? + (parent as ContextLocals).rootContext : + parent; + } + return _rootContext; + } + + bool hasProperty(String prop) { + return _locals.containsKey(prop) || + parent is ContextLocals && (parent as ContextLocals).hasProperty(prop); + } void operator[]=(String prop, value) { _locals[prop] = value; @@ -22,6 +36,11 @@ class LocalContext { dynamic operator[](String prop) { assert(hasProperty(prop)); + var context = this; + while (!context._locals.containsKey(prop)) { + // todo(vicb) cache context where prop is defined + context = context.parent; + } return _locals[prop]; } } diff --git a/lib/core/module.dart b/lib/core/module.dart index ff3ec5763..bcf585eb2 100644 --- a/lib/core/module.dart +++ b/lib/core/module.dart @@ -64,7 +64,7 @@ export "package:angular/core/module_internal.dart" show Interpolate, VmTurnZone, RootScope, - LocalContext, + ContextLocals, Scope, ScopeDigestTTL, ScopeEvent, diff --git a/lib/core/parser/dynamic_parser.dart b/lib/core/parser/dynamic_parser.dart index 041ebb33d..d90bc0e49 100644 --- a/lib/core/parser/dynamic_parser.dart +++ b/lib/core/parser/dynamic_parser.dart @@ -12,13 +12,6 @@ import 'package:angular/core/parser/eval.dart'; import 'package:angular/core/parser/utils.dart' show EvalError; import 'package:angular/utils.dart'; -abstract class ClosureMap { - Getter lookupGetter(String name); - Setter lookupSetter(String name); - Symbol lookupSymbol(String name); - MethodClosure lookupFunction(String name, CallArguments arguments); -} - @Injectable() class DynamicParser implements Parser { final Lexer _lexer; diff --git a/lib/core/parser/parser.dart b/lib/core/parser/parser.dart index 0f9839cd0..0fb5b62f0 100644 --- a/lib/core/parser/parser.dart +++ b/lib/core/parser/parser.dart @@ -67,3 +67,10 @@ abstract class ParserBackend { T newLiteralNumber(num value) => newLiteralPrimitive(value); T newLiteralString(String value) => null; } + +abstract class ClosureMap { + Getter lookupGetter(String name); + Setter lookupSetter(String name); + Symbol lookupSymbol(String name); + MethodClosure lookupFunction(String name, CallArguments arguments); +} diff --git a/lib/core/registry_dynamic.dart b/lib/core/registry_dynamic.dart index 54ea6573d..08e27f872 100644 --- a/lib/core/registry_dynamic.dart +++ b/lib/core/registry_dynamic.dart @@ -3,9 +3,51 @@ library angular.core_dynamic; import 'dart:mirrors'; import 'package:angular/core/annotation_src.dart'; import 'package:angular/core/registry.dart'; +export 'package:angular/core/registry.dart' show MetadataExtractor; -export 'package:angular/core/registry.dart' show - MetadataExtractor; +import 'package:angular/core/parser/parser.dart'; +import 'package:angular/change_detection/watch_group.dart' show ContextLocals; +import 'package:angular/core/parser/parser_dynamic.dart' show DynamicClosureMap; + +@MirrorsUsed(targets: const [ DynamicClosureMapLocalsAware ], metaTargets: const [] ) + +class DynamicClosureMapLocalsAware extends DynamicClosureMap { + var getter; + Getter lookupGetter(String name) { + return (o) { + if (o is ContextLocals) { + var ctx = o as ContextLocals; + if (ctx.hasProperty(name)) return ctx[name]; + o = ctx.rootContext; + } + if (getter == null) getter = super.lookupGetter(name); + return getter(o); + }; + } + + Setter lookupSetter(String name) { + var setter = super.lookupSetter(name); + return (o, value) { + return o is ContextLocals ? + setter(o.rootContext, value) : + setter(o, value); + }; + } + + MethodClosure lookupFunction(String name, CallArguments arguments) { + var fn = super.lookupFunction(name, arguments); + return (o, posArgs, namedArgs) { + if (o is ContextLocals) { + var ctx = o as ContextLocals; + if (ctx.hasProperty(name)) { + return fn({name: ctx[name]}, posArgs, namedArgs); + } + o = ctx.rootContext; + } + fn(o, posArgs, namedArgs); + }; + } +} var _fieldMetadataCache = new Map>(); diff --git a/lib/core/scope.dart b/lib/core/scope.dart index f81e392d0..9dcfb094a 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -258,7 +258,7 @@ class Scope { expression is String || expression is Function); if (expression is String && expression.isNotEmpty) { - var ctx = locals == null ? context : new LocalContext(context, locals); + var ctx = locals == null ? context : new ContextLocals(context, locals); return rootScope._parser(expression).eval(ctx); } @@ -1084,7 +1084,6 @@ class ExpressionVisitor implements syntax.Visitor { final ClosureMap _closureMap; AST contextRef = scopeContextRef; - ExpressionVisitor(this._closureMap); AST ast; @@ -1103,8 +1102,7 @@ class ExpressionVisitor implements syntax.Visitor { AST visitCollection(syntax.Expression exp) => new CollectionAST(visit(exp)); AST _mapToAst(syntax.Expression expression) => visit(expression); - List _toAst(List expressions) => - expressions.map(_mapToAst).toList(); + List _toAst(List expressions) => expressions.map(_mapToAst).toList(); Map _toAstMap(Map expressions) { if (expressions.isEmpty) return const {}; @@ -1125,37 +1123,47 @@ class ExpressionVisitor implements syntax.Visitor { Map named = _toAstMap(exp.arguments.named); ast = new MethodAST(visit(exp.object), exp.name, positionals, named); } + void visitAccessScope(syntax.AccessScope exp) { ast = new FieldReadAST(contextRef, exp.name); } + void visitAccessMember(syntax.AccessMember exp) { ast = new FieldReadAST(visit(exp.object), exp.name); } + void visitBinary(syntax.Binary exp) { ast = new PureFunctionAST(exp.operation, _operationToFunction(exp.operation), [visit(exp.left), visit(exp.right)]); } + + void visitPrefix(syntax.Prefix exp) { ast = new PureFunctionAST(exp.operation, _operationToFunction(exp.operation), [visit(exp.expression)]); } + void visitConditional(syntax.Conditional exp) { ast = new PureFunctionAST('?:', _operation_ternary, [visit(exp.condition), visit(exp.yes), visit(exp.no)]); } + void visitAccessKeyed(syntax.AccessKeyed exp) { ast = new ClosureAST('[]', _operation_bracket, [visit(exp.object), visit(exp.key)]); } + void visitLiteralPrimitive(syntax.LiteralPrimitive exp) { ast = new ConstantAST(exp.value); } + void visitLiteralString(syntax.LiteralString exp) { ast = new ConstantAST(exp.value); } + void visitLiteralArray(syntax.LiteralArray exp) { List items = _toAst(exp.elements); ast = new PureFunctionAST('[${items.join(', ')}]', new ArrayFn(), items); @@ -1187,15 +1195,19 @@ class ExpressionVisitor implements syntax.Visitor { void visitCallFunction(syntax.CallFunction exp) { _notSupported("function's returing functions"); } + void visitAssign(syntax.Assign exp) { _notSupported('assignement'); } + void visitLiteral(syntax.Literal exp) { _notSupported('literal'); } + void visitExpression(syntax.Expression exp) { _notSupported('?'); } + void visitChain(syntax.Chain exp) { _notSupported(';'); } diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 1ed2cb20f..06fd97331 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -121,7 +121,7 @@ class ElementBinder { } _bindCallback(dstPathFn, controller, expression, scope) { - dstPathFn.assign(controller, _parser(expression).bind(scope.context, ScopeLocals.wrapper)); + dstPathFn.assign(controller, _parser(expression).bind(scope.context, ContextLocals.wrapper)); } _createAttrMappings(controller, scope, List mappings, nodeAttrs, formatters, tasks) { diff --git a/lib/core_dom/module_internal.dart b/lib/core_dom/module_internal.dart index 491e62b2c..21c32972d 100644 --- a/lib/core_dom/module_internal.dart +++ b/lib/core_dom/module_internal.dart @@ -14,7 +14,7 @@ import 'package:angular/core/parser/parser.dart'; import 'package:angular/core_dom/dom_util.dart' as util; // todo vicb -import 'package:angular/change_detection/watch_group.dart' show Watch, LocalContext; +import 'package:angular/change_detection/watch_group.dart' show Watch, ContextLocals; import 'package:angular/core/registry.dart'; import 'package:angular/directive/module.dart' show NgBaseCss; diff --git a/lib/directive/ng_repeat.dart b/lib/directive/ng_repeat.dart index fb9dcba24..78464428a 100644 --- a/lib/directive/ng_repeat.dart +++ b/lib/directive/ng_repeat.dart @@ -112,7 +112,7 @@ class NgRepeat { ..[r'$index'] = index ..[r'$id'] = (obj) => obj; if (_keyIdentifier != null) context[_keyIdentifier] = key; - return relaxFnArgs(trackBy.eval)(new LocalContext(_scope.context, context)); + return relaxFnArgs(trackBy.eval)(new ContextLocals(_scope.context, context)); }); } @@ -151,8 +151,9 @@ class NgRepeat { var addRow = (int index, value, View previousView) { // todo vicb - var childContext = new LocalContext(_scope.context); - childContext = _updateContext(childContext, index, length, _valueIdentifier); + var childContext = new ContextLocals(_scope.context); + childContext = _updateContext(childContext, index, length); + childContext[_valueIdentifier] = value; var childScope = _scope.createChild(childContext); var view = _boundViewFactory(childScope); rows[index] = new _Row(_generateId(index, value, index), childScope, view); @@ -189,6 +190,7 @@ class NgRepeat { var previousRow = _rows[previousIndex]; var childScope = previousRow.scope; var childContext = _updateContext(childScope.context, index, length); + childContext[_valueIdentifier] = value; if (!identical(childScope.context[_valueIdentifier], value)) { childContext[_valueIdentifier] = value; } @@ -221,12 +223,11 @@ class NgRepeat { _rows = rows; } - LocalContext _updateContext(LocalContext context, int index, int len, [String valueId = null]) { + // todo(vicb): computeLocals + ContextLocals _updateContext(ContextLocals context, int index, int len) { var first = index == 0; var last = index == len - 1; - if (valueId != null) context[r'_valueIdentifier'] = valueId; - return context ..[r'$index'] = index ..[r'$first'] = first From 92f58bfc74fc6fa637ed393b309efb29bbddd4ad Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 15:32:10 +0200 Subject: [PATCH 08/29] optim --- lib/core/parser/parser_dynamic.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/core/parser/parser_dynamic.dart b/lib/core/parser/parser_dynamic.dart index 967db7bed..976f6e550 100644 --- a/lib/core/parser/parser_dynamic.dart +++ b/lib/core/parser/parser_dynamic.dart @@ -6,23 +6,26 @@ import 'package:angular/core/parser/parser.dart'; class DynamicClosureMap implements ClosureMap { final Map symbols = {}; + Getter lookupGetter(String name) { - var symbol = new Symbol(name); + var symbol; return (o) { if (o is Map) { return o[name]; } else { + if (symbol == null) symbol = lookupSymbol(name); return reflect(o).getField(symbol).reflectee; } }; } Setter lookupSetter(String name) { - var symbol = new Symbol(name); + var symbol; return (o, value) { if (o is Map) { return o[name] = value; } else { + if (symbol == null) symbol = lookupSymbol(name); reflect(o).setField(symbol, value); return value; } @@ -30,13 +33,9 @@ class DynamicClosureMap implements ClosureMap { } MethodClosure lookupFunction(String name, CallArguments arguments) { - var symbol = new Symbol(name); + var symbol; return (o, posArgs, namedArgs) { - var sNamedArgs = {}; - namedArgs.forEach((name, value) { - var symbol = symbols.putIfAbsent(name, () => new Symbol(name)); - sNamedArgs[symbol] = value; - }); + var sNamedArgs = new Map.fromIterables(namedArgs.keys.map(lookupSymbol), namedArgs.values); if (o is Map) { var fn = o[name]; if (fn is Function) { @@ -46,6 +45,7 @@ class DynamicClosureMap implements ClosureMap { } } else { try { + if (symbol == null) symbol = lookupSymbol(name); return reflect(o).invoke(symbol, posArgs, sNamedArgs).reflectee; } on NoSuchMethodError catch (e) { throw 'Undefined function $name'; @@ -54,5 +54,5 @@ class DynamicClosureMap implements ClosureMap { }; } - Symbol lookupSymbol(String name) => new Symbol(name); + Symbol lookupSymbol(String name) => symbols.putIfAbsent(name, () => new Symbol(name)); } From 1cd53f32881ab2face824ecb74ebf6a10914bb60 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 16:41:26 +0200 Subject: [PATCH 09/29] better impl --- lib/application_factory.dart | 2 +- lib/application_factory_static.dart | 3 +- lib/core/module.dart | 1 + lib/core/module_internal.dart | 1 + lib/core/registry_dynamic.dart | 44 ----------------------------- lib/core/scope.dart | 44 +++++++++++++++++++++++++++++ 6 files changed, 49 insertions(+), 46 deletions(-) diff --git a/lib/application_factory.dart b/lib/application_factory.dart index 8c46d4d4d..4df400484 100644 --- a/lib/application_factory.dart +++ b/lib/application_factory.dart @@ -62,7 +62,7 @@ class _DynamicApplication extends Application { ngModule ..bind(MetadataExtractor, toImplementation: DynamicMetadataExtractor) ..bind(FieldGetterFactory, toImplementation: DynamicFieldGetterFactory) - ..bind(ClosureMap, toImplementation: DynamicClosureMap); + ..bind(ClosureMap, toFactory: new ClosureMapLocalsAware(new DynamicClosureMap())); } Injector createInjector() => new DynamicInjector(modules: modules); diff --git a/lib/application_factory_static.dart b/lib/application_factory_static.dart index 2c4447722..46a6e3829 100644 --- a/lib/application_factory_static.dart +++ b/lib/application_factory_static.dart @@ -57,7 +57,8 @@ class _StaticApplication extends Application { ngModule ..bind(MetadataExtractor, toValue: new StaticMetadataExtractor(metadata)) ..bind(FieldGetterFactory, toValue: new StaticFieldGetterFactory(fieldGetters)) - ..bind(ClosureMap, toValue: new StaticClosureMap(fieldGetters, fieldSetters, symbols)); + ..bind(ClosureMap, toFactory: new ClosureMapLocalsAware( + new StaticClosureMap(fieldGetters, fieldSetters, symbols))); } Injector createInjector() => diff --git a/lib/core/module.dart b/lib/core/module.dart index bcf585eb2..6598f7e34 100644 --- a/lib/core/module.dart +++ b/lib/core/module.dart @@ -64,6 +64,7 @@ export "package:angular/core/module_internal.dart" show Interpolate, VmTurnZone, RootScope, + ClosureMapLocalsAware, ContextLocals, Scope, ScopeDigestTTL, diff --git a/lib/core/module_internal.dart b/lib/core/module_internal.dart index 6d13db95e..68367e687 100644 --- a/lib/core/module_internal.dart +++ b/lib/core/module_internal.dart @@ -52,5 +52,6 @@ class CoreModule extends Module { bind(DynamicParser); bind(DynamicParserBackend); bind(Lexer); + bind(ClosureMapLocalsAware); } } diff --git a/lib/core/registry_dynamic.dart b/lib/core/registry_dynamic.dart index 08e27f872..7306138cc 100644 --- a/lib/core/registry_dynamic.dart +++ b/lib/core/registry_dynamic.dart @@ -5,50 +5,6 @@ import 'package:angular/core/annotation_src.dart'; import 'package:angular/core/registry.dart'; export 'package:angular/core/registry.dart' show MetadataExtractor; -import 'package:angular/core/parser/parser.dart'; -import 'package:angular/change_detection/watch_group.dart' show ContextLocals; -import 'package:angular/core/parser/parser_dynamic.dart' show DynamicClosureMap; - -@MirrorsUsed(targets: const [ DynamicClosureMapLocalsAware ], metaTargets: const [] ) - -class DynamicClosureMapLocalsAware extends DynamicClosureMap { - var getter; - Getter lookupGetter(String name) { - return (o) { - if (o is ContextLocals) { - var ctx = o as ContextLocals; - if (ctx.hasProperty(name)) return ctx[name]; - o = ctx.rootContext; - } - if (getter == null) getter = super.lookupGetter(name); - return getter(o); - }; - } - - Setter lookupSetter(String name) { - var setter = super.lookupSetter(name); - return (o, value) { - return o is ContextLocals ? - setter(o.rootContext, value) : - setter(o, value); - }; - } - - MethodClosure lookupFunction(String name, CallArguments arguments) { - var fn = super.lookupFunction(name, arguments); - return (o, posArgs, namedArgs) { - if (o is ContextLocals) { - var ctx = o as ContextLocals; - if (ctx.hasProperty(name)) { - return fn({name: ctx[name]}, posArgs, namedArgs); - } - o = ctx.rootContext; - } - fn(o, posArgs, namedArgs); - }; - } -} - var _fieldMetadataCache = new Map>(); class DynamicMetadataExtractor implements MetadataExtractor { diff --git a/lib/core/scope.dart b/lib/core/scope.dart index 9dcfb094a..4f201ea77 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -1311,3 +1311,47 @@ class _FormatterWrapper extends FunctionApply { return value; } } + +@Injectable() +class ClosureMapLocalsAware implements ClosureMap { + final ClosureMap wrappedClsMap; + + ClosureMapLocalsAware(this.wrappedClsMap); + + Getter lookupGetter(String name) { + var getter; + return (o) { + if (o is ContextLocals) { + var ctx = o as ContextLocals; + if (ctx.hasProperty(name)) return ctx[name]; + o = ctx.rootContext; + } + if (getter == null) getter = wrappedClsMap.lookupGetter(name); + return getter(o); + }; + } + + Setter lookupSetter(String name) { + var setter = wrappedClsMap.lookupSetter(name); + return (o, value) { + return o is ContextLocals ? + setter(o.rootContext, value) : + setter(o, value); + }; + } + + MethodClosure lookupFunction(String name, CallArguments arguments) { + var fn = wrappedClsMap.lookupFunction(name, arguments); + return (o, pArgs, nArgs) { + if (o is ContextLocals) { + var ctx = o as ContextLocals; + if (ctx.hasProperty(name)) return fn({name: ctx[name]}, pArgs, nArgs); + o = ctx.rootContext; + } + return fn(o, pArgs, nArgs); + }; + } + + Symbol lookupSymbol(String name) => wrappedClsMap.lookupSymbol(name); +} + From b32dde791034ca8d5462d308ee96b70154c6dcaf Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 17:05:04 +0200 Subject: [PATCH 10/29] watch group locals aware --- .../dirty_checking_change_detector.dart | 51 ++++++++++--------- lib/change_detection/watch_group.dart | 44 ++++++++++------ lib/core/scope.dart | 40 --------------- 3 files changed, 56 insertions(+), 79 deletions(-) diff --git a/lib/change_detection/dirty_checking_change_detector.dart b/lib/change_detection/dirty_checking_change_detector.dart index 6d37cf0ab..dd1d7fe81 100644 --- a/lib/change_detection/dirty_checking_change_detector.dart +++ b/lib/change_detection/dirty_checking_change_detector.dart @@ -415,9 +415,10 @@ class DirtyCheckingRecord implements WatchRecord { * [DirtyCheckingRecord] into different access modes. If Object it sets up * reflection. If [Map] then it sets up map accessor. */ - void set object(obj) { - _object = obj; - if (obj == null) { + void set object(Object object) { + _object = object; + + if (object == null) { _mode = _MODE_IDENTITY_; _getter = null; return; @@ -425,7 +426,8 @@ class DirtyCheckingRecord implements WatchRecord { if (field == null) { _getter = null; - if (obj is Map) { + + if (object is Map) { if (_mode != _MODE_MAP_) { _mode = _MODE_MAP_; currentValue = new _MapChangeRecord(); @@ -437,8 +439,10 @@ class DirtyCheckingRecord implements WatchRecord { // new reference. currentValue._revertToPreviousState(); } + return; + } - } else if (obj is Iterable) { + if (object is Iterable) { if (_mode != _MODE_ITERABLE_) { _mode = _MODE_ITERABLE_; currentValue = new _CollectionChangeRecord(); @@ -450,6 +454,7 @@ class DirtyCheckingRecord implements WatchRecord { // new reference. currentValue._revertToPreviousState(); } + return; } else { _mode = _MODE_IDENTITY_; } @@ -457,30 +462,32 @@ class DirtyCheckingRecord implements WatchRecord { return; } - if (obj is ContextLocals) { - var ctx = obj as ContextLocals; + if (object is Map) { + _mode = _MODE_MAP_FIELD_; + _getter = null; + return; + } + + if (object is ContextLocals) { + var ctx = object as ContextLocals; if (ctx.hasProperty(field)) { - _object = obj; + _object = object; _mode = _MODE_MAP_FIELD_; _getter = null; return; } - obj = ctx.rootContext; + object = ctx.rootContext; } - if (obj is Map) { - _mode = _MODE_MAP_FIELD_; - _getter = null; - } else { - if (_fieldGetterFactory.isMethod(obj, field)) { - _mode = _MODE_IDENTITY_; - previousValue = currentValue = _fieldGetterFactory.method(obj, field)(obj); - assert(previousValue is Function); - } else { - _mode = _MODE_GETTER_; - _getter = _fieldGetterFactory.getter(obj, field); - } + if (_fieldGetterFactory.isMethod(object, field)) { + _mode = _MODE_IDENTITY_; + previousValue = currentValue = _fieldGetterFactory.method(object, field)(object); + assert(previousValue is Function); } + + _mode = _MODE_GETTER_; + _getter = _fieldGetterFactory.getter(object, field); + currentValue = _getter(object); } bool check() { @@ -532,8 +539,6 @@ class DirtyCheckingRecord implements WatchRecord { String toString() => '${_MODE_NAMES[_mode]}[$field]{$hashCode}'; } -final Object _INITIAL_ = new Object(); - class _MapChangeRecord implements MapChangeRecord { final _records = new Map(); Map _map; diff --git a/lib/change_detection/watch_group.dart b/lib/change_detection/watch_group.dart index b7eadcaa8..1ad115548 100644 --- a/lib/change_detection/watch_group.dart +++ b/lib/change_detection/watch_group.dart @@ -773,33 +773,45 @@ class _EvalWatchRecord implements WatchRecord<_Handler> { fn = null, name = null; - get field => '()'; + String get field => '()'; - get object => _object; + dynamic get object => _object; - set object(value) { + void set object(object) { assert(mode != _MODE_DELETED_); assert(mode != _MODE_MARKER_); assert(mode != _MODE_FUNCTION_); assert(mode != _MODE_PURE_FUNCTION_); assert(mode != _MODE_PURE_FUNCTION_APPLY_); - _object = value; + _object = object; - if (value == null) { + if (object == null) { mode = _MODE_NULL_; - } else { - if (value is Map) { - mode = _MODE_MAP_CLOSURE_; - } else { - if (_fieldGetterFactory.isMethod(value, name)) { - mode = _fieldGetterFactory.isMethodInvoke ? _MODE_METHOD_INVOKE_ : _MODE_METHOD_; - fn = _fieldGetterFactory.method(value, name); - } else { - mode = _MODE_FIELD_CLOSURE_; - fn = _fieldGetterFactory.getter(value, name); - } + return; + } + + if (object is Map) { + mode = _MODE_MAP_CLOSURE_; + return; + } + + if (object is ContextLocals) { + var ctx = object as ContextLocals; + if (ctx.hasProperty(name)) { + mode = _MODE_MAP_CLOSURE_; + return; } + object = ctx.rootContext; } + + if (_fieldGetterFactory.isMethod(object, name)) { + mode = _fieldGetterFactory.isMethodInvoke ? _MODE_METHOD_INVOKE_ : _MODE_METHOD_; + fn = _fieldGetterFactory.method(object, name); + return; + } + + mode = _MODE_FIELD_CLOSURE_; + fn = _fieldGetterFactory.getter(object, name); } bool check() { diff --git a/lib/core/scope.dart b/lib/core/scope.dart index 4f201ea77..a85984171 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -84,46 +84,6 @@ class ScopeDigestTTL { ScopeDigestTTL.value(this.ttl); } -//TODO(misko): I don't think this should be in scope. -class ScopeLocals implements Map { - static wrapper(scope, Map locals) => - new ScopeLocals(scope, locals); - - Map _scope; - Map _locals; - - ScopeLocals(this._scope, this._locals); - - void operator []=(String name, value) { - _scope[name] = value; - } - dynamic operator [](String name) { - // Map needed to clear Dart2js warning - Map map = _locals.containsKey(name) ? _locals : _scope; - return map[name]; - } - - bool get isEmpty => _scope.isEmpty && _locals.isEmpty; - bool get isNotEmpty => _scope.isNotEmpty || _locals.isNotEmpty; - List get keys => _scope.keys; - List get values => _scope.values; - int get length => _scope.length; - - void forEach(fn) { - _scope.forEach(fn); - } - dynamic remove(key) => _scope.remove(key); - void clear() { - _scope.clear; - } - bool containsKey(key) => _scope.containsKey(key); - bool containsValue(key) => _scope.containsValue(key); - void addAll(map) { - _scope.addAll(map); - } - dynamic putIfAbsent(key, fn) => _scope.putIfAbsent(key, fn); -} - /** * [Scope] is represents a collection of [watch]es [observe]ers, and [context] * for the watchers, observers and [eval]uations. Scopes structure loosely From e86c11835654d212154a9b4dc11c12365c2d379c Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 19:36:45 +0200 Subject: [PATCH 11/29] updates --- lib/application.dart | 15 ++++++++------- lib/core/scope.dart | 11 +++++------ lib/core_dom/element_binder.dart | 2 +- lib/directive/ng_class.dart | 6 ++++-- lib/directive/ng_switch.dart | 31 ++++++++++++++++--------------- 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/application.dart b/lib/application.dart index b04f5f7e4..b45eea03e 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -17,6 +17,7 @@ * main() { * applicationFactory() * .addModule(new MyModule()) + * .rootContextType(HelloWorldController) * .run(); * } * @@ -90,7 +91,6 @@ import 'package:angular/introspection_js.dart'; * about Angular services, formatters, and directives. When writing tests, this is typically done for * you by the [SetUpInjector](#angular-mock@id_setUpInjector) method. * - */ class AngularModule extends Module { AngularModule() { @@ -139,9 +139,7 @@ abstract class Application { final List modules = []; dom.Element element; -/** -* Creates a selector for a DOM element. -*/ + /// Creates a selector for a DOM element. dom.Element selector(String selector) => element = _find(selector); Application(): element = _find('[ng-app]', dom.window.document.documentElement) { @@ -151,9 +149,7 @@ abstract class Application { ..bind(dom.Node, toFactory: (i) => i.get(Application).element); } -/** -* Returns the injector for this module. -*/ + /// injector for this module. Injector injector; Application addModule(Module module) { @@ -161,6 +157,11 @@ abstract class Application { return this; } + Application rootContextType(Type rootContext) { + modules.add(new Module()..type(Object, implementedBy: rootContext)); + return this; + } + Injector run() { publishToJavaScript(); return zone.run(() { diff --git a/lib/core/scope.dart b/lib/core/scope.dart index a85984171..818b943a5 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -100,15 +100,14 @@ class Scope { */ // todo(vicb) was final var _context; - - get context => _context; - set context(ctx) { - - print("scope: setting context to $ctx"); + dynamic get context => _context; + void set context(ctx) { _context = ctx; - } + bool hasLocal(name) => _context is ContextLocals && (_context as ContextLocals).hasProperty(name); + dynamic getLocal(name) => (_context as ContextLocals)[name]; + /** * The [RootScope] of the application. */ diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 06fd97331..a0e804cb7 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -201,8 +201,8 @@ class ElementBinder { assert((linkMapTimer = _perf.startTimer('ng.view.link.map', ref.type)) != false); + // todo(vicb): delete if (ref.annotation is Controller) { - // todo(vicb) print("_link context = $controller"); scope.context = controller; } diff --git a/lib/directive/ng_class.dart b/lib/directive/ng_class.dart index 5fb9052a7..32e1ef11c 100644 --- a/lib/directive/ng_class.dart +++ b/lib/directive/ng_class.dart @@ -169,7 +169,8 @@ abstract class _NgClassBase { nodeAttrs.observe('class', (String cls) { if (prevCls != cls) { prevCls = cls; - _applyChanges(_scope.context[r'$index']); + var index = _scope.hasLocal(r'$index') ? _scope.getLocal(r'$index') : null; + _applyChanges(index); } }); } @@ -178,7 +179,8 @@ abstract class _NgClassBase { if (_watchExpression != null) _watchExpression.remove(); _watchExpression = _scope.watch(expression, (v, _) { _computeChanges(v); - _applyChanges(_scope.context[r'$index']); + var index = _scope.hasLocal(r'$index') ? _scope.getLocal(r'$index') : null; + _applyChanges(index); }, canChangeModel: false, collection: true); diff --git a/lib/directive/ng_switch.dart b/lib/directive/ng_switch.dart index cf2781c9e..4aa53f171 100644 --- a/lib/directive/ng_switch.dart +++ b/lib/directive/ng_switch.dart @@ -57,38 +57,39 @@ part of angular.directive; }, visibility: Directive.DIRECT_CHILDREN_VISIBILITY) class NgSwitch { - final cases = >{'?': <_Case>[]}; - final currentViews = <_ViewScopePair>[]; + final _cases = >{'?': <_Case>[]}; + final _currentViews = <_ViewAndPort>[]; Function onChange; - final Scope scope; + final Scope _scope; - NgSwitch(this.scope); + NgSwitch(this._scope); void addCase(String value, ViewPort anchor, BoundViewFactory viewFactory) { - cases.putIfAbsent(value, () => <_Case>[]).add(new _Case(anchor, viewFactory)); + _cases.putIfAbsent(value, () => <_Case>[]).add(new _Case(anchor, viewFactory)); } void set value(val) { - currentViews..forEach((_ViewScopePair pair) => pair.remove()) - ..clear(); + _currentViews..forEach((_ViewScopePair pair) => pair.remove()) + ..clear(); val = '!$val'; - (cases.containsKey(val) ? cases[val] : cases['?']) - .forEach((_Case caze) { - var view = caze.viewFactory(scope); - caze.port.insert(view); - currentViews.add(new _ViewScopePair(view, caze.port)); - }); + var cases = _cases.containsKey(val) ? _cases[val] : _cases['?']; + cases.forEach((_Case c) { + // todo (vicb) -> create Child ? + var view = c.viewFactory(_scope); + c.port.insert(view); + _currentViews.add(new _ViewAndPort(view, c.port)); + }); if (onChange != null) onChange(); } } -class _ViewScopePair { +class _ViewAndPort { final View _view; final ViewPort _port; - _ViewScopePair(this._view, this._port); + _ViewAndPort(this._view, this._port); void remove() { _port.remove(_view); From bafc1711323f3aa8fe4f785cf28a5919d1139842 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 25 Apr 2014 19:36:55 +0200 Subject: [PATCH 12/29] updates demos --- example/web/animation.dart | 3 +-- example/web/animation.html | 5 +++++ example/web/bouncing_balls.dart | 17 +++++++++-------- example/web/bouncing_balls.html | 6 +++--- example/web/hello_world.dart | 3 +-- example/web/hello_world.html | 2 +- example/web/todo.dart | 15 +++++---------- example/web/todo.html | 2 +- 8 files changed, 26 insertions(+), 27 deletions(-) diff --git a/example/web/animation.dart b/example/web/animation.dart index 67484d35c..164ec84bd 100644 --- a/example/web/animation.dart +++ b/example/web/animation.dart @@ -9,7 +9,6 @@ part 'animation/visibility_demo.dart'; part 'animation/stress_demo.dart'; part 'animation/css_demo.dart'; -@Controller(selector: '[animation-demo]') class AnimationDemo { final pages = ["About", "ng-repeat", "Visibility", "Css", "Stress Test"]; var currentPage = "About"; @@ -22,11 +21,11 @@ class AnimationDemoModule extends Module { bind(VisibilityDemo); bind(StressDemo); bind(CssDemo); - bind(AnimationDemo); } } main() { applicationFactory() .addModule(new AnimationDemoModule()) + .rootContextType(AnimationDemo) .run(); } diff --git a/example/web/animation.html b/example/web/animation.html index ddc5e5d41..ffc73c0e3 100644 --- a/example/web/animation.html +++ b/example/web/animation.html @@ -12,8 +12,11 @@ {{page}} + + diff --git a/example/web/bouncing_balls.dart b/example/web/bouncing_balls.dart index 2df0eba53..c2f934099 100644 --- a/example/web/bouncing_balls.dart +++ b/example/web/bouncing_balls.dart @@ -26,7 +26,6 @@ class BallModel { } -@Controller(selector: '[bounce-controller]') class BounceController { var lastTime = window.performance.now(); var run = false; @@ -34,10 +33,9 @@ class BounceController { var digestTime = 0; var currentDigestTime = 0; var balls = []; - final Scope scope; var ballClassName = 'ball'; - BounceController(this.scope) { + BounceController() { changeCount(100); if (run) tick(); } @@ -70,9 +68,10 @@ class BounceController { void timeDigest() { var start = window.performance.now(); digestTime = currentDigestTime; - scope.rootScope.domRead(() { - currentDigestTime = window.performance.now() - start; - }); +// todo(vicb) +// scope.rootScope.domRead(() { +// currentDigestTime = window.performance.now() - start; +// }); } void tick() { @@ -122,11 +121,13 @@ class BallPosition { class MyModule extends Module { MyModule() { - bind(BounceController); bind(BallPosition); } } main() { - applicationFactory().addModule(new MyModule()).run(); + applicationFactory() + .rootContextType(BounceController) + .addModule(new MyModule()) + .run(); } diff --git a/example/web/bouncing_balls.html b/example/web/bouncing_balls.html index fa7c8b8a5..f90e398fb 100644 --- a/example/web/bouncing_balls.html +++ b/example/web/bouncing_balls.html @@ -40,7 +40,7 @@
@@ -50,8 +50,8 @@
- {{bounce.fps}} fps. ({{bounce.balls.length}} balls) [{{1000/bounce.fps}} ms]
- Digest: {{bounce.digestTime}} ms
+ {{ fps }} fps. ({{ balls.length }} balls) [{{ 1000 / fps }} ms]
+ Digest: {{ digestTime }} ms
+1 +10 +100 diff --git a/example/web/hello_world.dart b/example/web/hello_world.dart index 53fbfb615..6d055bc78 100644 --- a/example/web/hello_world.dart +++ b/example/web/hello_world.dart @@ -1,13 +1,12 @@ import 'package:angular/angular.dart'; import 'package:angular/application_factory.dart'; -@Controller(selector: '[hello-world-controller]') class HelloWorld { String name = "world"; } main() { applicationFactory() - .addModule(new Module()..bind(HelloWorld)) + .rootContextType(HelloWorld) .run(); } diff --git a/example/web/hello_world.html b/example/web/hello_world.html index 475238794..07c259aa9 100644 --- a/example/web/hello_world.html +++ b/example/web/hello_world.html @@ -5,7 +5,7 @@ -

Hello {{name}}!

+

Hello {{ name }}!

name: diff --git a/example/web/todo.dart b/example/web/todo.dart index fa4b098fc..27460be5c 100644 --- a/example/web/todo.dart +++ b/example/web/todo.dart @@ -90,18 +90,12 @@ class Todo { main() { print(window.location.search); - var module = new Module() - ..bind(Todo) - ..bind(PlaybackHttpBackendConfig); + var module = new Module()..bind(PlaybackHttpBackendConfig); // If these is a query in the URL, use the server-backed // TodoController. Otherwise, use the stored-data controller. var query = window.location.search; - if (query.contains('?')) { - module.bind(Server, toImplementation: HttpServer); - } else { - module.bind(Server, toImplementation: NoOpServer); - } + module.bind(Server, toImplementation: query.contains('?') ? HttpServer : NoOpServer); if (query == '?record') { print('Using recording HttpBackend'); @@ -116,6 +110,7 @@ main() { } applicationFactory() - .addModule(module..type(Object, implementedBy: Todo)) - .run(); + .addModule(module) + .rootContextType(Todo) + .run(); } diff --git a/example/web/todo.html b/example/web/todo.html index 605912a24..2dcb69f4a 100644 --- a/example/web/todo.html +++ b/example/web/todo.html @@ -11,7 +11,7 @@
Wait, Dart is loading this awesome app...
-
+

Things To Do ;-)

From ca6537de33af0e029cddbe713dd4fbdf13b8daf2 Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 28 Apr 2014 16:04:42 +0200 Subject: [PATCH 13/29] style --- lib/core_dom/element_binder.dart | 9 ++++----- lib/core_dom/tagging_compiler.dart | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index a0e804cb7..a65919ff9 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -80,8 +80,7 @@ class ElementBinder { return _directiveCache = decorators; } - bool get hasDirectivesOrEvents => - _usableDirectiveRefs.isNotEmpty || onEvents.isNotEmpty; + bool get hasDirectivesOrEvents => _usableDirectiveRefs.isNotEmpty || onEvents.isNotEmpty; _bindTwoWay(tasks, expression, scope, dstPathFn, controller, formatters, dstExpression) { var taskId = tasks.registerTask(); @@ -190,7 +189,7 @@ class ElementBinder { }); } - _link(nodeInjector, probe, scope, nodeAttrs, formatters) { + void _link(nodeInjector, probe, scope, nodeAttrs, formatters) { _usableDirectiveRefs.forEach((DirectiveRef ref) { var linkTimer; try { @@ -239,8 +238,8 @@ class ElementBinder { }); } - _createDirectiveFactories(DirectiveRef ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs, - visibility) { + void _createDirectiveFactories(DirectiveRef ref, nodeModule, node, nodesAttrsDirectives, + nodeAttrs, visibility) { if (ref.type == TextMustache) { nodeModule.bind(TextMustache, toFactory: (Injector injector) { return new TextMustache(node, ref.value, injector.get(Interpolate), diff --git a/lib/core_dom/tagging_compiler.dart b/lib/core_dom/tagging_compiler.dart index a03007428..8f9b1579a 100644 --- a/lib/core_dom/tagging_compiler.dart +++ b/lib/core_dom/tagging_compiler.dart @@ -19,7 +19,7 @@ class TaggingCompiler implements Compiler { List elementBinders) { var node = domCursor.current; - if (node.nodeType == 1) { + if (node.nodeType == dom.Node.ELEMENT_NODE) { // If nodetype is a element, call selector matchElement. // If text, call selector.matchText From dd6aba6fcec14ce8ddfec22218b403178aa73c58 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 12:08:23 +0200 Subject: [PATCH 14/29] minor --- lib/core_dom/element_binder.dart | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index a65919ff9..5ee2d44a7 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -24,14 +24,12 @@ class TemplateElementBinder extends ElementBinder { String toString() => "[TemplateElementBinder template:$template]"; - _registerViewFactory(node, parentInjector, nodeModule) { + void _registerViewFactory(node, parentInjector, nodeModule) { assert(templateViewFactory != null); nodeModule - ..bind(ViewPort, toFactory: (_) => - new ViewPort(node, parentInjector.get(Animate))) - ..bind(ViewFactory, toValue: templateViewFactory) - ..bind(BoundViewFactory, toFactory: (Injector injector) => - templateViewFactory.bind(injector)); + ..bind(ViewPort, toFactory: (_) => new ViewPort(node, parentInjector.get(Animate))) + ..bind(ViewFactory, toValue: templateViewFactory) + ..bind(BoundViewFactory, toFactory: (Injector inj) => templateViewFactory.bind(inj)); } } @@ -82,7 +80,7 @@ class ElementBinder { bool get hasDirectivesOrEvents => _usableDirectiveRefs.isNotEmpty || onEvents.isNotEmpty; - _bindTwoWay(tasks, expression, scope, dstPathFn, controller, formatters, dstExpression) { + void _bindTwoWay(tasks, expression, scope, dstPathFn, controller, formatters, dstExpression) { var taskId = tasks.registerTask(); Expression expressionFn = _parser(expression); @@ -109,7 +107,7 @@ class ElementBinder { } } - _bindOneWay(tasks, expression, scope, dstPathFn, controller, formatters) { + void _bindOneWay(tasks, expression, scope, dstPathFn, controller, formatters) { var taskId = tasks.registerTask(); Expression attrExprFn = _parser(expression); @@ -119,11 +117,12 @@ class ElementBinder { }, formatters: formatters); } - _bindCallback(dstPathFn, controller, expression, scope) { + void _bindCallback(dstPathFn, controller, expression, scope) { dstPathFn.assign(controller, _parser(expression).bind(scope.context, ContextLocals.wrapper)); } - _createAttrMappings(controller, scope, List mappings, nodeAttrs, formatters, tasks) { + void _createAttrMappings(controller, scope, List mappings, nodeAttrs, + formatters, tasks) { mappings.forEach((MappingParts p) { var attrName = p.attrName; var dstExpression = p.dstExpression; @@ -138,8 +137,7 @@ class ElementBinder { var bindAttr = bindAttrs["bind-${p.attrName}"]; if (bindAttr != null) { if (p.mode == '<=>') { - _bindTwoWay(tasks, bindAttr, scope, dstPathFn, - controller, formatters, dstExpression); + _bindTwoWay(tasks, bindAttr, scope, dstPathFn, controller, formatters, dstExpression); } else if(p.mode == '&') { _bindCallback(dstPathFn, controller, bindAttr, scope); } else { @@ -166,8 +164,7 @@ class ElementBinder { case '=>': // one-way if (nodeAttrs[attrName] == null) return; - _bindOneWay(tasks, nodeAttrs[attrName], scope, - dstPathFn, controller, formatters); + _bindOneWay(tasks, nodeAttrs[attrName], scope, dstPathFn, controller, formatters); break; case '=>!': // one-way, one-time @@ -274,7 +271,7 @@ class ElementBinder { } // Overridden in TemplateElementBinder - _registerViewFactory(node, parentInjector, nodeModule) { + void _registerViewFactory(node, parentInjector, nodeModule) { nodeModule..bind(ViewPort, toValue: null) ..bind(ViewFactory, toValue: null) ..bind(BoundViewFactory, toValue: null); From 0c16576e18f4bd077daebfb53915c5a3c7cc3180 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 15:37:02 +0200 Subject: [PATCH 15/29] fixes --- lib/application.dart | 2 +- lib/application_factory.dart | 2 +- lib/application_factory_static.dart | 20 ++++++++++---------- lib/core/module_internal.dart | 1 - lib/directive/ng_include.dart | 6 ++---- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/application.dart b/lib/application.dart index b45eea03e..f0fe9325c 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -158,7 +158,7 @@ abstract class Application { } Application rootContextType(Type rootContext) { - modules.add(new Module()..type(Object, implementedBy: rootContext)); + modules.add(new Module()..bind(Object, toImplementation: rootContext)); return this; } diff --git a/lib/application_factory.dart b/lib/application_factory.dart index 4df400484..26d75ced5 100644 --- a/lib/application_factory.dart +++ b/lib/application_factory.dart @@ -62,7 +62,7 @@ class _DynamicApplication extends Application { ngModule ..bind(MetadataExtractor, toImplementation: DynamicMetadataExtractor) ..bind(FieldGetterFactory, toImplementation: DynamicFieldGetterFactory) - ..bind(ClosureMap, toFactory: new ClosureMapLocalsAware(new DynamicClosureMap())); + ..bind(ClosureMap, toFactory: (_) => new ClosureMapLocalsAware(new DynamicClosureMap())); } Injector createInjector() => new DynamicInjector(modules: modules); diff --git a/lib/application_factory_static.dart b/lib/application_factory_static.dart index 46a6e3829..ce5d4cc61 100644 --- a/lib/application_factory_static.dart +++ b/lib/application_factory_static.dart @@ -57,7 +57,7 @@ class _StaticApplication extends Application { ngModule ..bind(MetadataExtractor, toValue: new StaticMetadataExtractor(metadata)) ..bind(FieldGetterFactory, toValue: new StaticFieldGetterFactory(fieldGetters)) - ..bind(ClosureMap, toFactory: new ClosureMapLocalsAware( + ..bind(ClosureMap, toFactory: (_) => new ClosureMapLocalsAware( new StaticClosureMap(fieldGetters, fieldSetters, symbols))); } @@ -68,7 +68,7 @@ class _StaticApplication extends Application { * * Bootstraps Angular as part of the `main()` function. * -* `staticApplication()` replaces `dynamicApplication()` in the main function during pub build, +* `staticApplication()` replaces `dynamicApplication()` in the main function during pub build, * and is populated with the getters, setters, annotations, and factories generated by * Angular's transformers for dart2js compilation. It is not typically called directly. * @@ -76,20 +76,20 @@ class _StaticApplication extends Application { * * main() { * applicationFactory() -* .addModule(new Module()..bind(HelloWorld)) -* .run(); +* .rootContextType(HelloWorld) +* .run(); * } * * becomes: * * main() { * staticApplication(generated_static_injector.factories, -* generated_static_metadata.typeAnnotations, -* generated_static_expressions.getters, -* generated_static_expressions.setters, -* generated_static_expressions.symbols) -* .addModule(new Module()..bind(HelloWorldController)) -* .run(); +* generated_static_metadata.typeAnnotations, +* generated_static_expressions.getters, +* generated_static_expressions.setters, +* generated_static_expressions.symbols) +* .rootContextType(HelloWorld) +* .run(); * */ Application staticApplicationFactory( diff --git a/lib/core/module_internal.dart b/lib/core/module_internal.dart index 68367e687..6d13db95e 100644 --- a/lib/core/module_internal.dart +++ b/lib/core/module_internal.dart @@ -52,6 +52,5 @@ class CoreModule extends Module { bind(DynamicParser); bind(DynamicParserBackend); bind(Lexer); - bind(ClosureMapLocalsAware); } } diff --git a/lib/directive/ng_include.dart b/lib/directive/ng_include.dart index 981693eb9..361d0c959 100644 --- a/lib/directive/ng_include.dart +++ b/lib/directive/ng_include.dart @@ -29,7 +29,7 @@ class NgInclude { NgInclude(this._element, this._scope, this._viewCache, this._injector, this._directives); - void set url(value) { + void set url(String value) { _cleanUp(); if (value != null && value != '') { _viewCache.fromUrl(value, _directives).then(_updateContent); @@ -43,9 +43,7 @@ class NgInclude { _view = null; } - void _updateContent(createView) { - // create a new scope - _scope = scope.createChild(new PrototypeMap(scope.context)); + void _updateContent(ViewFactory createView) { _view = createView(new Module()..bind(Scope, toValue: _scope)); _view.nodes.forEach((node) => element.append(node)); From b26a3ea276d4047c52b50ba3a7943c5139109bd2 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 17:00:18 +0200 Subject: [PATCH 16/29] fix (transcluding cmp are working) - still one issue with ng-click (on-click works) --- lib/core_dom/event_handler.dart | 35 +++--- .../transcluding_component_factory.dart | 3 +- lib/directive/ng_bind.dart | 2 +- lib/directive/ng_events.dart | 107 +++++++++--------- 4 files changed, 69 insertions(+), 78 deletions(-) diff --git a/lib/core_dom/event_handler.dart b/lib/core_dom/event_handler.dart index 30b5ee432..f6dfadd74 100644 --- a/lib/core_dom/event_handler.dart +++ b/lib/core_dom/event_handler.dart @@ -20,7 +20,7 @@ typedef void EventFunction(event); *
* * @Component(selector: '[foo]') - * class FooController { + * class FooComponent { * void say(String something) { * print(something); * } @@ -50,31 +50,25 @@ class EventHandler { } void _eventListener(dom.Event event) { - dom.Node element = event.target; - while (element != null && element != _rootNode) { + for (dom.Node el = event.target; el != null && el != _rootNode; el = el.parentNode) { var expression; - if (element is dom.Element) - expression = (element as dom.Element).attributes[eventNameToAttrName(event.type)]; + if (el is dom.Element) + expression = (el as dom.Element).attributes[eventNameToAttrName(event.type)]; if (expression != null) { try { - var scope = _getScope(element); + var scope = _getScope(el); if (scope != null) scope.eval(expression); } catch (e, s) { _exceptionHandler(e, s); } } - element = element.parentNode; } } - Scope _getScope(dom.Node element) { - // var topElement = (rootNode is dom.ShadowRoot) ? rootNode.parentNode : rootNode; - while (element != _rootNode.parentNode) { - ElementProbe probe = _expando[element]; - if (probe != null) { - return probe.scope; - } - element = element.parentNode; + Scope _getScope(dom.Node el) { + for (;el != _rootNode.parentNode; el = el.parentNode) { + ElementProbe probe = _expando[el]; + if (probe != null) return probe.scope; } return null; } @@ -84,10 +78,10 @@ class EventHandler { * be transformed into on-some-custom-event. */ static String eventNameToAttrName(String eventName) { - var part = eventName.replaceAllMapped(new RegExp("([A-Z])"), (Match match) { + var part = eventName.replaceAllMapped(new RegExp('([A-Z])'), (Match match) { return '-${match.group(0).toLowerCase()}'; }); - return 'on-${part}'; + return 'on-$part'; } /** @@ -95,18 +89,17 @@ class EventHandler { * corresponds to event named 'someCustomEvent'. */ static String attrNameToEventName(String attrName) { - var part = attrName.startsWith("on-") ? attrName.substring(3) : attrName; + var part = attrName.startsWith('on-') ? attrName.substring(3) : attrName; part = part.replaceAllMapped(new RegExp(r'\-(\w)'), (Match match) { return match.group(0).toUpperCase(); }); - return part.replaceAll("-", ""); + return part.replaceAll('-', ''); } } @Injectable() class ShadowRootEventHandler extends EventHandler { - ShadowRootEventHandler(dom.ShadowRoot shadowRoot, - Expando expando, + ShadowRootEventHandler(dom.ShadowRoot shadowRoot, Expando expando, ExceptionHandler exceptionHandler) : super(shadowRoot, expando, exceptionHandler); } diff --git a/lib/core_dom/transcluding_component_factory.dart b/lib/core_dom/transcluding_component_factory.dart index f298e4188..b4f419f9f 100644 --- a/lib/core_dom/transcluding_component_factory.dart +++ b/lib/core_dom/transcluding_component_factory.dart @@ -107,14 +107,13 @@ class TranscludingComponentFactory implements ComponentFactory { ..bind(ref.type) ..bind(NgElement) ..bind(ContentPort, toValue: contentPort) - ..bind(Scope, toValue: shadowScope) + ..bind(Scope, toFactory: (i) => scope.createChild(i.get(ref.type))) ..bind(TemplateLoader, toValue: templateLoader) ..bind(dom.ShadowRoot, toValue: new ShadowlessShadowRoot(element)) ..bind(ElementProbe, toFactory: (_) => probe); childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME); var controller = childInjector.get(ref.type); - shadowScope.context = controller; ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); return controller; }; diff --git a/lib/directive/ng_bind.dart b/lib/directive/ng_bind.dart index 04346cb0e..062b0f8c9 100644 --- a/lib/directive/ng_bind.dart +++ b/lib/directive/ng_bind.dart @@ -8,7 +8,7 @@ part of angular.directive; * Typically, you don't use ngBind directly, but instead you use the double * curly markup like {{ expression }} which is similar but less verbose. * - * It is preferrable to use ngBind instead of {{ expression }} when a template + * It is preferable to use ngBind instead of {{ expression }} when a template * is momentarily displayed by the browser in its raw state before Angular * compiles it. Since ngBind is an element attribute, it makes the bindings * invisible to the user while the page is loading. diff --git a/lib/directive/ng_events.dart b/lib/directive/ng_events.dart index 14c422d3f..b7fdd10a7 100644 --- a/lib/directive/ng_events.dart +++ b/lib/directive/ng_events.dart @@ -134,10 +134,9 @@ class NgEvent { // object? One would pretty much only assign to one or two of those // properties. I'm opting for the map since it's less boilerplate code. var listeners = {}; - final dom.Element element; - final Scope scope; + final dom.Element _element; - NgEvent(this.element, this.scope); + NgEvent(this._element); // NOTE: Do not use the element.on['some_event'].listen(...) syntax. Doing so // has two downsides: @@ -155,55 +154,55 @@ class NgEvent { } } - set onAbort(value) => initListener(element.onAbort, value); - set onBeforeCopy(value) => initListener(element.onBeforeCopy, value); - set onBeforeCut(value) => initListener(element.onBeforeCut, value); - set onBeforePaste(value) => initListener(element.onBeforePaste, value); - set onBlur(value) => initListener(element.onBlur, value); - set onChange(value) => initListener(element.onChange, value); - set onClick(value) => initListener(element.onClick, value); - set onContextMenu(value) => initListener(element.onContextMenu, value); - set onCopy(value) => initListener(element.onCopy, value); - set onCut(value) => initListener(element.onCut, value); - set onDoubleClick(value) => initListener(element.onDoubleClick, value); - set onDrag(value) => initListener(element.onDrag, value); - set onDragEnd(value) => initListener(element.onDragEnd, value); - set onDragEnter(value) => initListener(element.onDragEnter, value); - set onDragLeave(value) => initListener(element.onDragLeave, value); - set onDragOver(value) => initListener(element.onDragOver, value); - set onDragStart(value) => initListener(element.onDragStart, value); - set onDrop(value) => initListener(element.onDrop, value); - set onError(value) => initListener(element.onError, value); - set onFocus(value) => initListener(element.onFocus, value); - set onFullscreenChange(value) => initListener(element.onFullscreenChange, value); - set onFullscreenError(value) => initListener(element.onFullscreenError, value); - set onInput(value) => initListener(element.onInput, value); - set onInvalid(value) => initListener(element.onInvalid, value); - set onKeyDown(value) => initListener(element.onKeyDown, value); - set onKeyPress(value) => initListener(element.onKeyPress, value); - set onKeyUp(value) => initListener(element.onKeyUp, value); - set onLoad(value) => initListener(element.onLoad, value); - set onMouseDown(value) => initListener(element.onMouseDown, value); - set onMouseEnter(value) => initListener(element.onMouseEnter, value); - set onMouseLeave(value) => initListener(element.onMouseLeave, value); - set onMouseMove(value) => initListener(element.onMouseMove, value); - set onMouseOut(value) => initListener(element.onMouseOut, value); - set onMouseOver(value) => initListener(element.onMouseOver, value); - set onMouseUp(value) => initListener(element.onMouseUp, value); - set onMouseWheel(value) => initListener(element.onMouseWheel, value); - set onPaste(value) => initListener(element.onPaste, value); - set onReset(value) => initListener(element.onReset, value); - set onScroll(value) => initListener(element.onScroll, value); - set onSearch(value) => initListener(element.onSearch, value); - set onSelect(value) => initListener(element.onSelect, value); - set onSelectStart(value) => initListener(element.onSelectStart, value); -// set onSpeechChange(value) => initListener(element.onSpeechChange, value); - set onSubmit(value) => initListener(element.onSubmit, value); - set onTouchCancel(value) => initListener(element.onTouchCancel, value); - set onTouchEnd(value) => initListener(element.onTouchEnd, value); - set onTouchEnter(value) => initListener(element.onTouchEnter, value); - set onTouchLeave(value) => initListener(element.onTouchLeave, value); - set onTouchMove(value) => initListener(element.onTouchMove, value); - set onTouchStart(value) => initListener(element.onTouchStart, value); - set onTransitionEnd(value) => initListener(element.onTransitionEnd, value); + set onAbort(value) => initListener(_element.onAbort, value); + set onBeforeCopy(value) => initListener(_element.onBeforeCopy, value); + set onBeforeCut(value) => initListener(_element.onBeforeCut, value); + set onBeforePaste(value) => initListener(_element.onBeforePaste, value); + set onBlur(value) => initListener(_element.onBlur, value); + set onChange(value) => initListener(_element.onChange, value); + set onClick(value) => initListener(_element.onClick, value); + set onContextMenu(value) => initListener(_element.onContextMenu, value); + set onCopy(value) => initListener(_element.onCopy, value); + set onCut(value) => initListener(_element.onCut, value); + set onDoubleClick(value) => initListener(_element.onDoubleClick, value); + set onDrag(value) => initListener(_element.onDrag, value); + set onDragEnd(value) => initListener(_element.onDragEnd, value); + set onDragEnter(value) => initListener(_element.onDragEnter, value); + set onDragLeave(value) => initListener(_element.onDragLeave, value); + set onDragOver(value) => initListener(_element.onDragOver, value); + set onDragStart(value) => initListener(_element.onDragStart, value); + set onDrop(value) => initListener(_element.onDrop, value); + set onError(value) => initListener(_element.onError, value); + set onFocus(value) => initListener(_element.onFocus, value); + set onFullscreenChange(value) => initListener(_element.onFullscreenChange, value); + set onFullscreenError(value) => initListener(_element.onFullscreenError, value); + set onInput(value) => initListener(_element.onInput, value); + set onInvalid(value) => initListener(_element.onInvalid, value); + set onKeyDown(value) => initListener(_element.onKeyDown, value); + set onKeyPress(value) => initListener(_element.onKeyPress, value); + set onKeyUp(value) => initListener(_element.onKeyUp, value); + set onLoad(value) => initListener(_element.onLoad, value); + set onMouseDown(value) => initListener(_element.onMouseDown, value); + set onMouseEnter(value) => initListener(_element.onMouseEnter, value); + set onMouseLeave(value) => initListener(_element.onMouseLeave, value); + set onMouseMove(value) => initListener(_element.onMouseMove, value); + set onMouseOut(value) => initListener(_element.onMouseOut, value); + set onMouseOver(value) => initListener(_element.onMouseOver, value); + set onMouseUp(value) => initListener(_element.onMouseUp, value); + set onMouseWheel(value) => initListener(_element.onMouseWheel, value); + set onPaste(value) => initListener(_element.onPaste, value); + set onReset(value) => initListener(_element.onReset, value); + set onScroll(value) => initListener(_element.onScroll, value); + set onSearch(value) => initListener(_element.onSearch, value); + set onSelect(value) => initListener(_element.onSelect, value); + set onSelectStart(value) => initListener(_element.onSelectStart, value); +// set onSpeechChange(value) => initListener(_element.onSpeechChange, value); + set onSubmit(value) => initListener(_element.onSubmit, value); + set onTouchCancel(value) => initListener(_element.onTouchCancel, value); + set onTouchEnd(value) => initListener(_element.onTouchEnd, value); + set onTouchEnter(value) => initListener(_element.onTouchEnter, value); + set onTouchLeave(value) => initListener(_element.onTouchLeave, value); + set onTouchMove(value) => initListener(_element.onTouchMove, value); + set onTouchStart(value) => initListener(_element.onTouchStart, value); + set onTransitionEnd(value) => initListener(_element.onTransitionEnd, value); } From cf0f5dabae6d8b8a93f7f6a985208cc94c0f47a3 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 17:58:24 +0200 Subject: [PATCH 17/29] fix ng-click issue --- lib/change_detection/prototype_map.dart | 5 +++-- lib/core/parser/eval_access.dart | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/change_detection/prototype_map.dart b/lib/change_detection/prototype_map.dart index d616ae8b2..779a09767 100644 --- a/lib/change_detection/prototype_map.dart +++ b/lib/change_detection/prototype_map.dart @@ -1,6 +1,6 @@ part of angular.watch_group; -// todo(vicb) rename to ContextLocals + rename the file +// todo(vicb) rename the file class ContextLocals { // todo(vicb) _parentContext final Object parent; @@ -37,10 +37,11 @@ class ContextLocals { dynamic operator[](String prop) { assert(hasProperty(prop)); var context = this; + while (!context._locals.containsKey(prop)) { // todo(vicb) cache context where prop is defined context = context.parent; } - return _locals[prop]; + return context._locals[prop]; } } diff --git a/lib/core/parser/eval_access.dart b/lib/core/parser/eval_access.dart index 0fdfa61c0..f3212be1b 100644 --- a/lib/core/parser/eval_access.dart +++ b/lib/core/parser/eval_access.dart @@ -45,7 +45,9 @@ abstract class AccessFast { _eval(holder) { if (holder == null) return null; - return (holder is Map) ? holder[name] : getter(holder); + if (holder is ContextLocals) return (holder as ContextLocals)[name]; + if (holder is Map) return holder[name]; + return getter(holder); } _assign(scope, holder, value) { @@ -53,7 +55,9 @@ abstract class AccessFast { _assignToNonExisting(scope, value); return value; } else { - return (holder is Map) ? (holder[name] = value) : setter(holder, value); + if (holder is ContextLocals) return (holder as ContextLocals)[name] = value; + if (holder is Map) return holder[name] = value; + return setter(holder, value); } } From a816acbfe3f1be363d8876d49a7facf64b3f7d7d Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 18:33:26 +0200 Subject: [PATCH 18/29] add some todos --- lib/core/parser/eval_access.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core/parser/eval_access.dart b/lib/core/parser/eval_access.dart index f3212be1b..b6b801b2e 100644 --- a/lib/core/parser/eval_access.dart +++ b/lib/core/parser/eval_access.dart @@ -38,19 +38,21 @@ class AccessKeyed extends syntax.AccessKeyed { * where we have a pair of pre-compiled getter and setter functions that we * use to do the access the field. */ +// todo(vicb) - parser should not depend on ContextLocals +// todo(vicb) - Map should not be a special case so that we can access the props abstract class AccessFast { String get name; Getter get getter; Setter get setter; - _eval(holder) { + dynamic _eval(holder) { if (holder == null) return null; if (holder is ContextLocals) return (holder as ContextLocals)[name]; if (holder is Map) return holder[name]; return getter(holder); } - _assign(scope, holder, value) { + dynamic _assign(scope, holder, value) { if (holder == null) { _assignToNonExisting(scope, value); return value; From 852f0692fe8385ac58f1009d298c5d8f4c7392e1 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 19:05:58 +0200 Subject: [PATCH 19/29] fix shadow components --- .../shadow_dom_component_factory.dart | 54 +++++++++---------- .../transcluding_component_factory.dart | 5 +- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/core_dom/shadow_dom_component_factory.dart b/lib/core_dom/shadow_dom_component_factory.dart index 0c128893a..33c4d6c41 100644 --- a/lib/core_dom/shadow_dom_component_factory.dart +++ b/lib/core_dom/shadow_dom_component_factory.dart @@ -1,5 +1,10 @@ part of angular.core.dom_internal; +/** + * [ComponentFactory] is responsible for setting up components. This includes + * the shadowDom, fetching template, importing styles, setting up attribute + * mappings, publishing the controller, and compiling and caching the template. + */ abstract class ComponentFactory { FactoryFn call(dom.Node node, DirectiveRef ref); @@ -42,25 +47,15 @@ class ShadowDomComponentFactory implements ComponentFactory { final directives = injector.get(DirectiveMap); final baseCss = injector.get(NgBaseCss); // This is a bit of a hack since we are returning different type then we are. - var componentFactory = new _ComponentFactory(node, ref.type, component, + var componentFactory = new _ShadowDomComponentFactory(node, ref.type, component, injector.get(dom.NodeTreeSanitizer), _expando, baseCss, _styleElementCache); - var controller = componentFactory.call(injector, scope, viewCache, http, templateCache, - directives); - componentFactory.shadowScope.context = controller; - return controller; + return componentFactory.call(injector, scope, viewCache, http, templateCache, directives); }; } } - -/** - * ComponentFactory is responsible for setting up components. This includes - * the shadowDom, fetching template, importing styles, setting up attribute - * mappings, publishing the controller, and compiling and caching the template. - */ -class _ComponentFactory implements Function { - +class _ShadowDomComponentFactory implements Function { final dom.Element element; final Type type; final Component component; @@ -74,17 +69,16 @@ class _ComponentFactory implements Function { Injector shadowInjector; var controller; - _ComponentFactory(this.element, this.type, this.component, this.treeSanitizer, - this._expando, this._baseCss, this._styleElementCache); + _ShadowDomComponentFactory(this.element, this.type, this.component, this.treeSanitizer, + this._expando, this._baseCss, this._styleElementCache); dynamic call(Injector injector, Scope scope, ViewCache viewCache, Http http, TemplateCache templateCache, DirectiveMap directives) { shadowDom = element.createShadowRoot() - ..applyAuthorStyles = component.applyAuthorStyles - ..resetStyleInheritance = component.resetStyleInheritance; + ..applyAuthorStyles = component.applyAuthorStyles + ..resetStyleInheritance = component.resetStyleInheritance; - shadowScope = scope.createChild({}); // Isolate // TODO(pavelgj): fetching CSS with Http is mainly an attempt to // work around an unfiled Chrome bug when reloading same CSS breaks // styles all over the page. We shouldn't be doing browsers work, @@ -117,7 +111,9 @@ class _ComponentFactory implements Function { } return shadowDom; })); - controller = createShadowInjector(injector, templateLoader).get(type); + + var shadowInjector = createShadowInjector(scope, injector, templateLoader); + var controller = shadowInjector.get(type); ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); return controller; } @@ -128,19 +124,23 @@ class _ComponentFactory implements Function { return shadowDom; } - Injector createShadowInjector(injector, TemplateLoader templateLoader) { + Injector createShadowInjector(Scope scope, Injector injector, TemplateLoader templateLoader) { var probe; var shadowModule = new Module() - ..bind(type) - ..bind(NgElement) - ..bind(EventHandler, toImplementation: ShadowRootEventHandler) - ..bind(Scope, toValue: shadowScope) - ..bind(TemplateLoader, toValue: templateLoader) - ..bind(dom.ShadowRoot, toValue: shadowDom) - ..bind(ElementProbe, toFactory: (_) => probe); + ..bind(type) + ..bind(NgElement) + ..bind(EventHandler, toImplementation: ShadowRootEventHandler) + ..bind(Scope, toFactory: (inj) => scope.createChild(inj.get(type))) + ..bind(TemplateLoader, toValue: templateLoader) + ..bind(dom.ShadowRoot, toValue: shadowDom) + ..bind(ElementProbe, toFactory: (_) => probe); + shadowInjector = injector.createChild([shadowModule], name: SHADOW_DOM_INJECTOR_NAME); + shadowScope = shadowInjector.get(Scope); + probe = _expando[shadowDom] = new ElementProbe( injector.get(ElementProbe), shadowDom, shadowInjector, shadowScope); + return shadowInjector; } } diff --git a/lib/core_dom/transcluding_component_factory.dart b/lib/core_dom/transcluding_component_factory.dart index b4f419f9f..2082d4b46 100644 --- a/lib/core_dom/transcluding_component_factory.dart +++ b/lib/core_dom/transcluding_component_factory.dart @@ -100,8 +100,6 @@ class TranscludingComponentFactory implements ComponentFactory { } TemplateLoader templateLoader = new TemplateLoader(elementFuture); - Scope shadowScope = scope.createChild({}); - var probe; var childModule = new Module() ..bind(ref.type) @@ -114,7 +112,8 @@ class TranscludingComponentFactory implements ComponentFactory { childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME); var controller = childInjector.get(ref.type); - ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); + var childScope = childInjector.get(Scope); + ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, childScope); return controller; }; } From 26e118febbbc72595ce35d8c4a8fa3518498dc51 Mon Sep 17 00:00:00 2001 From: Victor Date: Thu, 1 May 2014 19:21:47 +0200 Subject: [PATCH 20/29] restore animation demo - issue in CSS demo --- example/web/animation.html | 3 --- lib/core/parser/eval_access.dart | 12 ++++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/example/web/animation.html b/example/web/animation.html index ffc73c0e3..5373d98c4 100644 --- a/example/web/animation.html +++ b/example/web/animation.html @@ -12,8 +12,6 @@ {{page}} - - diff --git a/lib/core/parser/eval_access.dart b/lib/core/parser/eval_access.dart index b6b801b2e..f5abbfbdf 100644 --- a/lib/core/parser/eval_access.dart +++ b/lib/core/parser/eval_access.dart @@ -47,8 +47,12 @@ abstract class AccessFast { dynamic _eval(holder) { if (holder == null) return null; - if (holder is ContextLocals) return (holder as ContextLocals)[name]; if (holder is Map) return holder[name]; + if (holder is ContextLocals) { + var ctx = holder as ContextLocals; + if (ctx.hasProperty(name)) return ctx[name]; + holder = ctx.rootContext; + } return getter(holder); } @@ -57,8 +61,12 @@ abstract class AccessFast { _assignToNonExisting(scope, value); return value; } else { - if (holder is ContextLocals) return (holder as ContextLocals)[name] = value; if (holder is Map) return holder[name] = value; + if (holder is ContextLocals) { + var ctx = holder as ContextLocals; + if (ctx.hasProperty(name)) return ctx[name] = value; + holder = ctx.rootContext; + } return setter(holder, value); } } From a4380f2f88b08eb71fb256fed2aec72b49819774 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 10:12:31 +0200 Subject: [PATCH 21/29] minor --- lib/core/scope.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/core/scope.dart b/lib/core/scope.dart index 818b943a5..a9eecc7df 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -1271,7 +1271,6 @@ class _FormatterWrapper extends FunctionApply { } } -@Injectable() class ClosureMapLocalsAware implements ClosureMap { final ClosureMap wrappedClsMap; From 744bcf7d5ced75cf3e434530a8f4f53062bb595b Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 10:16:22 +0200 Subject: [PATCH 22/29] Remove the Controller class --- lib/application.dart | 7 ----- lib/application_factory.dart | 1 - lib/application_factory_static.dart | 8 +---- lib/core/annotation.dart | 1 - lib/core/annotation_src.dart | 49 +---------------------------- lib/core_dom/element_binder.dart | 12 ------- lib/transformer.dart | 1 - 7 files changed, 2 insertions(+), 77 deletions(-) diff --git a/lib/application.dart b/lib/application.dart index f0fe9325c..e9a30092e 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -8,15 +8,8 @@ * import 'package:angular/angular.dart'; * import 'package:angular/application_factory.dart'; * - * class MyModule extends Module { - * MyModule() { - * bind(HelloWorldController); - * } - * } - * * main() { * applicationFactory() - * .addModule(new MyModule()) * .rootContextType(HelloWorldController) * .run(); * } diff --git a/lib/application_factory.dart b/lib/application_factory.dart index 26d75ced5..26706a4a6 100644 --- a/lib/application_factory.dart +++ b/lib/application_factory.dart @@ -51,7 +51,6 @@ import 'dart:html'; metaTargets: const [ Injectable, Decorator, - Controller, Component, Formatter ]) diff --git a/lib/application_factory_static.dart b/lib/application_factory_static.dart index ce5d4cc61..2f0d0ebc0 100644 --- a/lib/application_factory_static.dart +++ b/lib/application_factory_static.dart @@ -11,15 +11,9 @@ * import 'package:angular/angular.dart'; * import 'package:angular/application_factory_static.dart'; * - * class MyModule extends Module { - * MyModule() { - * bind(HelloWorldController); - * } - * } - * * main() { * staticApplicationFactory() - * .addModule(new MyModule()) + * .rootContextType(HelloWorldController) * .run(); * } * diff --git a/lib/core/annotation.dart b/lib/core/annotation.dart index 768def9aa..dcd2f23fd 100644 --- a/lib/core/annotation.dart +++ b/lib/core/annotation.dart @@ -15,7 +15,6 @@ export "package:angular/core/annotation_src.dart" show Directive, Component, - Controller, Decorator, DirectiveAnnotation, diff --git a/lib/core/annotation_src.dart b/lib/core/annotation_src.dart index 926e5fa15..b6369324d 100644 --- a/lib/core/annotation_src.dart +++ b/lib/core/annotation_src.dart @@ -34,7 +34,7 @@ class Injectable { } /** - * Abstract supper class of [Controller], [Component], and [Decorator]. + * Abstract supper class of [Component], and [Decorator]. */ abstract class Directive { @@ -391,53 +391,6 @@ class Decorator extends Directive { exportExpressionAttrs: exportExpressionAttrs); } -/** - * Meta-data marker placed on a class which should act as a controller for your - * application. - * - * Controllers are essentially [Decorator]s with few key differences: - * - * * Controllers create a new scope at the element. - * * Controllers should not do any DOM manipulation. - * * Controllers are meant for application-logic - * (rather then DOM manipulation logic which directives are meant for.) - * - * Controllers can implement [AttachAware], [DetachAware] and - * declare these optional methods: - * - * * `attach()` - Called on first [Scope.apply()]. - * * `detach()` - Called on when owning scope is destroyed. - */ -@deprecated -class Controller extends Decorator { - const Controller({ - children: Directive.COMPILE_CHILDREN, - map, - module, - selector, - visibility, - exportExpressions, - exportExpressionAttrs - }) - : super(selector: selector, - children: children, - visibility: visibility, - map: map, - module: module, - exportExpressions: exportExpressions, - exportExpressionAttrs: exportExpressionAttrs); - - Directive _cloneWithNewMap(newMap) => - new Controller( - children: children, - module: module, - map: newMap, - selector: selector, - visibility: visibility, - exportExpressions: exportExpressions, - exportExpressionAttrs: exportExpressionAttrs); -} - /** * Abstract supper class of [NgAttr], [NgCallback], [NgOneWay], [NgOneWayOneTime], and [NgTwoWay]. */ diff --git a/lib/core_dom/element_binder.dart b/lib/core_dom/element_binder.dart index 5ee2d44a7..3a79d3251 100644 --- a/lib/core_dom/element_binder.dart +++ b/lib/core_dom/element_binder.dart @@ -196,13 +196,6 @@ class ElementBinder { probe.directives.add(controller); assert((linkMapTimer = _perf.startTimer('ng.view.link.map', ref.type)) != false); - - // todo(vicb): delete - if (ref.annotation is Controller) { - print("_link context = $controller"); - scope.context = controller; - } - var tasks = new _TaskList(controller is AttachAware ? () {if (scope.isAttached) controller.attach();} : null); @@ -301,11 +294,6 @@ class ElementBinder { directiveRefs.forEach((DirectiveRef ref) { Directive annotation = ref.annotation; - if (annotation is Controller) { - //todo(vicb) - scope = scope.createChild(scope.context); - nodeModule.bind(Scope, toValue: scope); - } _createDirectiveFactories(ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs, annotation.visibility); diff --git a/lib/transformer.dart b/lib/transformer.dart index 0d8668203..5f2f888bb 100644 --- a/lib/transformer.dart +++ b/lib/transformer.dart @@ -36,7 +36,6 @@ TransformOptions _parseSettings(Map args) { var annotations = [ 'angular.core.annotation_src.Injectable', 'angular.core.annotation_src.Decorator', - 'angular.core.annotation_src.Controller', 'angular.core.annotation_src.Component', 'angular.core.annotation_src.Formatter']; annotations.addAll(_readStringListValue(args, 'injectable_annotations')); From f5e7c6fe5c5b4adfec513c39846f5568f5ce432e Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 10:20:47 +0200 Subject: [PATCH 23/29] Scope: re-make Scope.context final --- lib/core/scope.dart | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/core/scope.dart b/lib/core/scope.dart index a9eecc7df..14541e705 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -98,15 +98,10 @@ class Scope { /** * The default execution context for [watch]es [observe]ers, and [eval]uation. */ - // todo(vicb) was final - var _context; - dynamic get context => _context; - void set context(ctx) { - _context = ctx; - } + final context; - bool hasLocal(name) => _context is ContextLocals && (_context as ContextLocals).hasProperty(name); - dynamic getLocal(name) => (_context as ContextLocals)[name]; + bool hasLocal(name) => context is ContextLocals && (context as ContextLocals).hasProperty(name); + dynamic getLocal(name) => (context as ContextLocals)[name]; /** * The [RootScope] of the application. @@ -152,12 +147,9 @@ class Scope { /// Do not use. Exposes internal state for testing. bool get hasOwnStreams => _streams != null && _streams._scope == this; - // todo(vicb) this.context - Scope(Object _context, this.rootScope, this._parentScope, + Scope(this.context, this.rootScope, this._parentScope, this._readWriteGroup, this._readOnlyGroup, this.id, - this._stats) { - context = _context; - } + this._stats); /** * Use [watch] to set up change detection on an expression. From 37bf55d3a08dbf3cf867728f7cdd54f7c863ab4c Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 10:22:42 +0200 Subject: [PATCH 24/29] Remove debug prints --- lib/core_dom/mustache.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/core_dom/mustache.dart b/lib/core_dom/mustache.dart index 616c67df3..1cc242c15 100644 --- a/lib/core_dom/mustache.dart +++ b/lib/core_dom/mustache.dart @@ -12,8 +12,6 @@ class TextMustache { FormatterMap formatters) { String expression = interpolate(template); - print('Mustache: watching $expression'); - scope.watch(expression, _updateMarkup, canChangeModel: false, @@ -21,7 +19,6 @@ class TextMustache { } void _updateMarkup(text, previousText) { - print('Mustache: changed $previousText -> $text'); _element.text = text; } } From 1b6621bae514a080b767d98b5243434904edcd77 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 10:44:02 +0200 Subject: [PATCH 25/29] minor (style) --- example/web/bouncing_balls.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/web/bouncing_balls.dart b/example/web/bouncing_balls.dart index c2f934099..1c3225170 100644 --- a/example/web/bouncing_balls.dart +++ b/example/web/bouncing_balls.dart @@ -79,7 +79,7 @@ class BounceController { var delay = now - lastTime; fps = (1000/delay).round(); - for(var i=0, ii=balls.length; i Date: Fri, 2 May 2014 10:52:34 +0200 Subject: [PATCH 26/29] style: Scope stats --- lib/core/scope.dart | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/core/scope.dart b/lib/core/scope.dart index 14541e705..11ca4904c 100644 --- a/lib/core/scope.dart +++ b/lib/core/scope.dart @@ -339,11 +339,11 @@ class ScopeStats { final evalStopwatch = new AvgStopwatch(); final processStopwatch = new AvgStopwatch(); - List _digestLoopTimes = []; + final _digestLoopTimes = []; int _flushPhaseDuration = 0 ; int _assertFlushPhaseDuration = 0; - int _loopNo = 0; + int _loopNo; ScopeStatsEmitter _emitter; ScopeStatsConfig _config; @@ -353,7 +353,7 @@ class ScopeStats { ScopeStats(this._emitter, this._config); void digestStart() { - _digestLoopTimes = []; + _digestLoopTimes.clear(); _stopwatchReset(); _loopNo = 0; } @@ -373,10 +373,9 @@ class ScopeStats { void digestLoop(int changeCount) { _loopNo++; if (_config.emit && _emitter != null) { - _emitter.emit(_loopNo.toString(), fieldStopwatch, evalStopwatch, - processStopwatch); + _emitter.emit(_loopNo.toString(), fieldStopwatch, evalStopwatch, processStopwatch); } - _digestLoopTimes.add( _allStagesDuration() ); + _digestLoopTimes.add(_allStagesDuration()); _stopwatchReset(); } @@ -387,23 +386,25 @@ class ScopeStats { void domWriteEnd() {} void domReadStart() {} void domReadEnd() {} + void flushStart() { _stopwatchReset(); } + void flushEnd() { if (_config.emit && _emitter != null) { - _emitter.emit(RootScope.STATE_FLUSH, fieldStopwatch, evalStopwatch, - processStopwatch); + _emitter.emit(RootScope.STATE_FLUSH, fieldStopwatch, evalStopwatch, processStopwatch); } _flushPhaseDuration = _allStagesDuration(); } + void flushAssertStart() { _stopwatchReset(); } + void flushAssertEnd() { if (_config.emit && _emitter != null) { - _emitter.emit(RootScope.STATE_FLUSH_ASSERT, fieldStopwatch, evalStopwatch, - processStopwatch); + _emitter.emit(RootScope.STATE_FLUSH_ASSERT, fieldStopwatch, evalStopwatch, processStopwatch); } _assertFlushPhaseDuration = _allStagesDuration(); } From 1848ac5da46a1731fae634520263aca851e9f7b3 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 12:39:50 +0200 Subject: [PATCH 27/29] minor: testbed --- lib/mock/test_bed.dart | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/mock/test_bed.dart b/lib/mock/test_bed.dart index e81f4d04e..fed2f92ea 100644 --- a/lib/mock/test_bed.dart +++ b/lib/mock/test_bed.dart @@ -27,10 +27,10 @@ class TestBed { * * - [String] then treat it as HTML * - [Node] then treat it as the root node - * - [List] then treat it as a collection of nods + * - [List] then treat it as a collection of nodes * * After the compilation the [rootElements] contains an array of compiled root nodes, - * and [rootElement] contains the first element from the [rootElemets]. + * and [rootElement] contains the first element from the [rootElements]. * * An option [scope] parameter can be supplied to link it with non root scope. */ @@ -48,7 +48,7 @@ class TestBed { } else { throw 'Expecting: String, Node, or List got $html.'; } - rootElement = rootElements.length > 0 && rootElements[0] is Element ? rootElements[0] : null; + rootElement = rootElements.isNotEmpty && rootElements[0] is Element ? rootElements[0] : null; if (directives == null) { directives = injector.get(DirectiveMap); } @@ -62,11 +62,7 @@ class TestBed { List toNodeList(html) { var div = new DivElement(); div.setInnerHtml(html, treeSanitizer: new NullTreeSanitizer()); - var nodes = []; - for (var node in div.nodes) { - nodes.add(node); - } - return nodes; + return new List.from(div.nodes); } /** @@ -81,7 +77,7 @@ class TestBed { /** * Select an [OPTION] in a [SELECT] with a given name and trigger the - * appropriate DOM event. Used when testing [SELECT] controlls in forms. + * appropriate DOM event. Used when testing [SELECT] controls in forms. */ selectOption(element, text) { element.querySelectorAll('option').forEach((o) => o.selected = o.text == text); @@ -98,5 +94,5 @@ class TestBed { throw 'Probe not found.'; } - getScope(Node node) => getProbe(node).scope; + Scope getScope(Node node) => getProbe(node).scope; } From 5c22f7a6c39bac93355900107c5007cd997c32ab Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 2 May 2014 12:40:01 +0200 Subject: [PATCH 28/29] squash: drop controller --- test/core/annotation_src_spec.dart | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/test/core/annotation_src_spec.dart b/test/core/annotation_src_spec.dart index 78a27f061..ddf508173 100644 --- a/test/core/annotation_src_spec.dart +++ b/test/core/annotation_src_spec.dart @@ -75,24 +75,4 @@ void main() => describe('annotations', () { expect(variables(cloneWithNewMap(decorator, {}))).toEqual(variables(decorator)); }); }); - - describe('controller', () { - it('should set all fields on clone when all the fields are set', () { - var controller = new Controller( - children: 'xxx', - map: {}, - selector: '', - module: (){}, - visibility: Directive.LOCAL_VISIBILITY, - exportExpressions: [], - exportExpressionAttrs: [] - ); - - // Check that no fields are null - expect(nullFields(controller)).toEqual([]); - - // Check that the clone is the same as the original. - expect(variables(cloneWithNewMap(controller, {}))).toEqual(variables(controller)); - }); - }); }); From cc78a1b2f6cd547de288123e1da61e1735e010ae Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 5 May 2014 12:43:41 +0200 Subject: [PATCH 29/29] fix rebase --- lib/directive/ng_switch.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/directive/ng_switch.dart b/lib/directive/ng_switch.dart index 4aa53f171..3ca0ad378 100644 --- a/lib/directive/ng_switch.dart +++ b/lib/directive/ng_switch.dart @@ -69,7 +69,7 @@ class NgSwitch { } void set value(val) { - _currentViews..forEach((_ViewScopePair pair) => pair.remove()) + _currentViews..forEach((_ViewAndPort vp) => vp.remove()) ..clear(); val = '!$val';