| Index: third_party/pkg/angular/test/core_dom/compiler_spec.dart
|
| diff --git a/third_party/pkg/angular/test/core_dom/compiler_spec.dart b/third_party/pkg/angular/test/core_dom/compiler_spec.dart
|
| index 53c8c580594a95e05174bc7c1909a939eb2274ab..f86eea9aa244aa1f61e06bfa439bfcae249cfb45 100644
|
| --- a/third_party/pkg/angular/test/core_dom/compiler_spec.dart
|
| +++ b/third_party/pkg/angular/test/core_dom/compiler_spec.dart
|
| @@ -3,468 +3,550 @@ library compiler_spec;
|
| import '../_specs.dart';
|
|
|
|
|
| -main() => describe('dte.compiler', () {
|
| - Compiler $compile;
|
| - DirectiveMap directives;
|
| - Injector injector;
|
| - Scope rootScope;
|
| +forBothCompilers(fn) {
|
| + describe('walking compiler', () {
|
| + beforeEachModule((Module m) {
|
| + m.type(Compiler, implementedBy: WalkingCompiler);
|
| + return m;
|
| + });
|
| + fn();
|
| + });
|
|
|
| - beforeEach(module((Module module) {
|
| + describe('tagging compiler', () {
|
| + beforeEachModule((Module m) {
|
| + m.type(Compiler, implementedBy: TaggingCompiler);
|
| + return m;
|
| + });
|
| + fn();
|
| + });
|
| +
|
| + describe('transcluding components', () {
|
| + beforeEachModule((Module m) {
|
| + m.type(Compiler, implementedBy: TaggingCompiler);
|
| + m.type(ComponentFactory, implementedBy: TranscludingComponentFactory);
|
| +
|
| + return m;
|
| + });
|
| + fn();
|
| + });
|
| +}
|
| +
|
| +void main() {
|
| + forBothCompilers(() =>
|
| + describe('dte.compiler', () {
|
| + TestBed _;
|
| +
|
| + beforeEachModule((Module module) {
|
| module
|
| - ..type(TabComponent)
|
| - ..type(PublishTypesAttrDirective)
|
| - ..type(PaneComponent)
|
| - ..type(SimpleTranscludeInAttachAttrDirective)
|
| - ..type(IncludeTranscludeAttrDirective)
|
| - ..type(LocalAttrDirective)
|
| - ..type(OneOfTwoDirectives)
|
| - ..type(TwoOfTwoDirectives)
|
| - ..type(MyController)
|
| - ..type(MyParentController)
|
| - ..type(MyChildController);
|
| - return (Injector _injector) {
|
| - injector = _injector;
|
| - $compile = injector.get(Compiler);
|
| - directives = injector.get(DirectiveMap);
|
| - rootScope = injector.get(Scope);
|
| - };
|
| - }));
|
| -
|
| - it('should compile basic hello world', inject(() {
|
| - var element = $('<div ng-bind="name"></div>');
|
| - var template = $compile(element, directives);
|
| -
|
| - rootScope.context['name'] = 'angular';
|
| - template(injector, element);
|
| -
|
| - expect(element.text()).toEqual('');
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('angular');
|
| - }));
|
| -
|
| - it('should not throw on an empty list', inject(() {
|
| - $compile([], directives);
|
| - }));
|
| -
|
| - it('should compile a directive in a child', inject(() {
|
| - var element = $('<div><div ng-bind="name"></div></div>');
|
| - var template = $compile(element, directives);
|
| -
|
| - rootScope.context['name'] = 'angular';
|
| -
|
| -
|
| - template(injector, element);
|
| -
|
| - expect(element.text()).toEqual('');
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('angular');
|
| - }));
|
| -
|
| - it('should compile repeater', inject(() {
|
| - var element = $('<div><div ng-repeat="item in items" ng-bind="item"></div></div>');
|
| - var template = $compile(element, directives);
|
| -
|
| - rootScope.context['items'] = ['A', 'b'];
|
| - template(injector, element);
|
| -
|
| - expect(element.text()).toEqual('');
|
| - // TODO(deboer): Digest twice until we have dirty checking in the scope.
|
| - rootScope.apply();
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('Ab');
|
| -
|
| - rootScope.context['items'] = [];
|
| - rootScope.apply();
|
| - expect(element.html()).toEqual('<!--ANCHOR: [ng-repeat]=item in items-->');
|
| - }));
|
| -
|
| - it('should compile repeater with children', inject((Compiler $compile) {
|
| - var element = $('<div><div ng-repeat="item in items"><div ng-bind="item"></div></div></div>');
|
| - var template = $compile(element, directives);
|
| -
|
| - rootScope.context['items'] = ['A', 'b'];
|
| - template(injector, element);
|
| -
|
| - expect(element.text()).toEqual('');
|
| - // TODO(deboer): Digest twice until we have dirty checking in the scope.
|
| - rootScope.apply();
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('Ab');
|
| -
|
| - rootScope.context['items'] = [];
|
| - rootScope.apply();
|
| - expect(element.html()).toEqual('<!--ANCHOR: [ng-repeat]=item in items-->');
|
| - }));
|
| -
|
| - it('should compile text', inject((Compiler $compile) {
|
| - var element = $('<div>{{name}}<span>!</span></div>').contents();
|
| - element.remove(null);
|
| -
|
| - var template = $compile(element, directives);
|
| -
|
| - rootScope.context['name'] = 'OK';
|
| - var block = template(injector, element);
|
| -
|
| - element = $(block.elements);
|
| -
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('OK!');
|
| - }));
|
| -
|
| - it('should compile nested repeater', inject((Compiler $compile) {
|
| - var element = $(
|
| + ..type(TabComponent)
|
| + ..type(PublishModuleAttrDirective)
|
| + ..type(PaneComponent)
|
| + ..type(SimpleTranscludeInAttachAttrDirective)
|
| + ..type(IgnoreChildrenDirective)
|
| + ..type(IncludeTranscludeAttrDirective)
|
| + ..type(LocalAttrDirective)
|
| + ..type(OneOfTwoDirectives)
|
| + ..type(TwoOfTwoDirectives)
|
| + ..type(MyController)
|
| + ..type(MyParentController)
|
| + ..type(MyChildController);
|
| + });
|
| +
|
| + beforeEach(inject((TestBed tb) => _ = tb));
|
| +
|
| + it('should compile basic hello world', () {
|
| + var element = _.compile('<div ng-bind="name"></div>');
|
| +
|
| + _.rootScope.context['name'] = 'angular';
|
| +
|
| + expect(element.text).toEqual('');
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('angular');
|
| + });
|
| +
|
| + it('should not throw on an empty list', () {
|
| + _.compile([]);
|
| + });
|
| +
|
| + it('should compile a comment on the top level', () {
|
| + _.compile('<!-- comment -->');
|
| + expect(_.rootElements[0]).toHaveHtml('<!-- comment -->');
|
| + });
|
| +
|
| + it('should compile a comment with no directives around', () {
|
| + var element = _.compile('<div><!-- comment --></div>');
|
| + expect(element).toHaveHtml('<!-- comment -->');
|
| + });
|
| +
|
| + it('should compile a comment when the parent has a directive', () {
|
| + var element = _.compile('<div ng-show="true"><!-- comment --></div>');
|
| + expect(element).toHaveHtml('<!-- comment -->');
|
| + });
|
| +
|
| + it('should compile a directive in a child', () {
|
| + var element = _.compile('<div><div ng-bind="name"></div></div>');
|
| +
|
| + _.rootScope.context['name'] = 'angular';
|
| +
|
| + expect(element.text).toEqual('');
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('angular');
|
| + });
|
| +
|
| + it('should compile repeater', () {
|
| + var element = _.compile('<div><div ng-repeat="item in items" ng-bind="item"></div></div>');
|
| +
|
| + _.rootScope.context['items'] = ['A', 'b'];
|
| + expect(element.text).toEqual('');
|
| +
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('Ab');
|
| +
|
| + _.rootScope.context['items'] = [];
|
| + _.rootScope.apply();
|
| + expect(element).toHaveHtml('<!--ANCHOR: [ng-repeat]=item in items-->');
|
| + });
|
| +
|
| + it('should compile a text child of a basic repeater', () {
|
| + var element = _.compile(
|
| + '<div ng-show="true">' +
|
| + '<span ng-repeat="r in [1, 2]">{{r}}</span>' +
|
| + '</div>');
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('12');
|
| + });
|
| +
|
| + it('should compile a text child of a repeat with a directive', () {
|
| + _.compile(
|
| + '<div ng-show="true">'
|
| + '<span ng-show=true" ng-repeat="r in robots">{{r}}</span>'
|
| + '</div>');
|
| + });
|
| +
|
| + it('should compile a sibling template directive', () {
|
| + var element = _.compile(
|
| + '<div ng-model="selected">'
|
| + '<option value="">blank</option>'
|
| + '<div ng-repeat="value in [1,2]" ng-value="value">{{value}}</div>'
|
| + '</div>');
|
| +
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('blank12');
|
| + });
|
| +
|
| + it('should compile repeater with children', (Compiler compile) {
|
| + var element = _.compile('<div><div ng-repeat="item in items"><div ng-bind="item"></div></div></div>');
|
| +
|
| + _.rootScope.context['items'] = ['A', 'b'];
|
| +
|
| + expect(element.text).toEqual('');
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('Ab');
|
| +
|
| + _.rootScope.context['items'] = [];
|
| + _.rootScope.apply();
|
| + expect(element).toHaveHtml('<!--ANCHOR: [ng-repeat]=item in items-->');
|
| + });
|
| +
|
| + it('should compile text', (Compiler compile) {
|
| + var element = _.compile('<div>{{name}}<span>!</span></div>');
|
| + _.rootScope.context['name'] = 'OK';
|
| +
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('OK!');
|
| + });
|
| +
|
| + it('should compile nested repeater', (Compiler compile) {
|
| + var element = _.compile(
|
| '<div>' +
|
| - '<ul ng-repeat="lis in uls">' +
|
| - '<li ng-repeat="li in lis">{{li}}</li>' +
|
| - '</ul>' +
|
| + '<ul ng-repeat="lis in uls">' +
|
| + '<li ng-repeat="li in lis">{{li}}</li>' +
|
| + '</ul>' +
|
| '</div>');
|
| - var template = $compile(element, directives);
|
|
|
| - rootScope.context['uls'] = [['A'], ['b']];
|
| - template(injector, element);
|
| + _.rootScope.context['uls'] = [['A'], ['b']];
|
|
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('Ab');
|
| - }));
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('Ab');
|
| + });
|
|
|
| - it('should compile two directives with the same selector', inject((Logger log) {
|
| - var element = $('<div two-directives></div>');
|
| - var template = $compile(element, directives);
|
| + it('should compile two directives with the same selector', (Logger log) {
|
| + var element = _.compile('<div two-directives></div>');
|
|
|
| - template(injector, element);
|
| - rootScope.apply();
|
| + _.rootScope.apply();
|
|
|
| expect(log).toEqual(['OneOfTwo', 'TwoOfTwo']);
|
| - }));
|
| + });
|
|
|
| + it('should compile a directive that ignores children', (Logger log) {
|
| + // The ng-repeat comes first, so it is not ignored, but the children *are*
|
| + var element = _.compile('<div ng-repeat="i in [1,2]" ignore-children><div two-directives></div></div>');
|
| +
|
| + _.rootScope.apply();
|
| +
|
| + expect(log).toEqual(['Ignore', 'Ignore']);
|
| + });
|
| +
|
| + it('should compile a text child after a directive child', () {
|
| + _.compile('<div><span ng-show="true">hi</span>{{hello}}</div>');
|
| + });
|
|
|
|
|
| describe("interpolation", () {
|
| - it('should interpolate attribute nodes', inject(() {
|
| - var element = $('<div test="{{name}}"></div>');
|
| - var template = $compile(element, directives);
|
| + it('should interpolate attribute nodes', () {
|
| + var element = _.compile('<div test="{{name}}"></div>');
|
|
|
| - rootScope.context['name'] = 'angular';
|
| - template(injector, element);
|
| + _.rootScope.context['name'] = 'angular';
|
|
|
| - rootScope.apply();
|
| - expect(element.attr('test')).toEqual('angular');
|
| - }));
|
| + _.rootScope.apply();
|
| + expect(element.attributes['test']).toEqual('angular');
|
| + });
|
|
|
| - it('should interpolate text nodes', inject(() {
|
| - var element = $('<div>{{name}}</div>');
|
| - var template = $compile(element, directives);
|
| + it('should interpolate text nodes', () {
|
| + var element = _.compile('<div>{{name}}</div>');
|
|
|
| - rootScope.context['name'] = 'angular';
|
| - template(injector, element);
|
| + _.rootScope.context['name'] = 'angular';
|
|
|
| - rootScope.apply();
|
| - expect(element.text()).toEqual('angular');
|
| - }));
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('angular');
|
| + });
|
| });
|
|
|
|
|
| describe('components', () {
|
| - beforeEach(module((Module module) {
|
| - module.type(SimpleComponent);
|
| - module.type(CamelCaseMapComponent);
|
| - module.type(IoComponent);
|
| - module.type(IoControllerComponent);
|
| - module.type(UnpublishedIoControllerComponent);
|
| - module.type(IncorrectMappingComponent);
|
| - module.type(NonAssignableMappingComponent);
|
| - module.type(ParentExpressionComponent);
|
| - module.type(PublishMeComponent);
|
| - module.type(PublishMeDirective);
|
| - module.type(LogComponent);
|
| - module.type(AttachDetachComponent);
|
| - module.type(SimpleAttachComponent);
|
| - module.type(SimpleComponent);
|
| - module.type(ExprAttrComponent);
|
| - module.type(SayHelloFilter);
|
| + beforeEachModule((Module module) {
|
| + module
|
| + ..type(CamelCaseMapComponent)
|
| + ..type(IoComponent)
|
| + ..type(IoControllerComponent)
|
| + ..type(UnpublishedIoControllerComponent)
|
| + ..type(IncorrectMappingComponent)
|
| + ..type(NonAssignableMappingComponent)
|
| + ..type(ParentExpressionComponent)
|
| + ..type(PublishMeComponent)
|
| + ..type(PublishMeDirective)
|
| + ..type(LogComponent)
|
| + ..type(AttachDetachComponent)
|
| + ..type(SimpleAttachComponent)
|
| + ..type(SimpleComponent)
|
| + ..type(SometimesComponent)
|
| + ..type(ExprAttrComponent)
|
| + ..type(LogElementComponent)
|
| + ..type(SayHelloFilter);
|
| + });
|
| +
|
| + it('should select on element', async(() {
|
| + var element = _.compile(r'<div><simple></simple></div>');
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('INNER()');
|
| }));
|
|
|
| - it('should select on element', async(inject((NgZone zone) {
|
| - var element = $(r'<div><simple></simple></div>');
|
| + it('should tranclude correctly', async(() {
|
| + var element = _.compile(r'<div><simple>trans</simple></div>');
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('INNER(trans)');
|
| + }));
|
|
|
| - zone.run(() {
|
| - BlockFactory blockFactory = $compile(element, directives);
|
| - Block block = blockFactory(injector, element);
|
| - });
|
| + it('should tranclude if content was not present initially', async(() {
|
| + var element = _.compile(r'<div>And <sometimes sometimes=sometimes>jump</sometimes></div>');
|
| + document.body.append(element);
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('And ');
|
|
|
| + _.rootScope.context['sometimes'] = true;
|
| microLeap();
|
| - expect(element.textWithShadow()).toEqual('INNER()');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('And jump');
|
| + }));
|
|
|
| - it('should create a simple component', async(inject((NgZone zone) {
|
| - rootScope.context['name'] = 'OUTTER';
|
| - var element = $(r'<div>{{name}}:<simple>{{name}}</simple></div>');
|
| + it('should redistribute content when the content tag disappears', async(() {
|
| + var element = _.compile(r'<div>And <sometimes sometimes=sometimes>jump</sometimes></div>');
|
| + document.body.append(element);
|
|
|
| - zone.run(() {
|
| - BlockFactory blockFactory = $compile(element, directives);
|
| - Block block = blockFactory(injector, element);
|
| - });
|
| + _.rootScope.context['sometimes'] = true;
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('And jump');
|
|
|
| + _.rootScope.context['sometimes'] = false;
|
| microLeap();
|
| - expect(element.textWithShadow()).toEqual('OUTTER:INNER(OUTTER)');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('And ');
|
|
|
| - it('should create a component that can access parent scope', async(inject((NgZone zone) {
|
| - rootScope.context['fromParent'] = "should not be used";
|
| - rootScope.context['val'] = "poof";
|
| - var element = $('<parent-expression from-parent=val></parent-expression>');
|
| + _.rootScope.context['sometimes'] = true;
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('And jump');
|
| + }));
|
| +
|
| + it('should store ElementProbe with Elements', async(() {
|
| + _.compile('<div><simple>innerText</simple></div>');
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + var simpleElement = _.rootElement.querySelector('simple');
|
| + expect(simpleElement).toHaveText('INNER(innerText)');
|
| + var simpleProbe = ngProbe(simpleElement);
|
| + var simpleComponent = simpleProbe.injector.get(SimpleComponent);
|
| + expect(simpleComponent.scope.context['name']).toEqual('INNER');
|
| + var shadowRoot = simpleElement.shadowRoot;
|
| +
|
| + // If there is no shadow root, skip this.
|
| + if (shadowRoot != null) {
|
| + var shadowProbe = ngProbe(shadowRoot);
|
| + expect(shadowProbe).toBeNotNull();
|
| + expect(shadowProbe.element).toEqual(shadowRoot);
|
| + expect(shadowProbe.parent.element).toEqual(simpleElement);
|
| + }
|
| + }));
|
| +
|
| + it('should create a simple component', async((VmTurnZone zone) {
|
| + _.rootScope.context['name'] = 'OUTTER';
|
| + var element = _.compile(r'<div>{{name}}:<simple>{{name}}</simple></div>');
|
| + microLeap();
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('OUTTER:INNER(OUTTER)');
|
| + }));
|
|
|
| - zone.run(() =>
|
| - $compile(element, directives)(injector, element));
|
| + it('should create a component that can access parent scope', async((VmTurnZone zone) {
|
| + _.rootScope.context['fromParent'] = "should not be used";
|
| + _.rootScope.context['val'] = "poof";
|
| + var element = _.compile('<parent-expression from-parent=val></parent-expression>');
|
|
|
| microLeap();
|
| - expect(renderedText(element)).toEqual('inside poof');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('inside poof');
|
| + }));
|
|
|
| - it('should behave nicely if a mapped attribute is missing', async(inject((NgZone zone) {
|
| - var element = $('<parent-expression></parent-expression>');
|
| - zone.run(() =>
|
| - $compile(element, directives)(injector, element));
|
| + it('should behave nicely if a mapped attribute is missing', async((VmTurnZone zone) {
|
| + var element = _.compile('<parent-expression></parent-expression>');
|
|
|
| microLeap();
|
| - expect(renderedText(element)).toEqual('inside ');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('inside ');
|
| + }));
|
|
|
| - it('should behave nicely if a mapped attribute evals to null', async(inject((NgZone zone) {
|
| - rootScope.context['val'] = null;
|
| - var element = $('<parent-expression fromParent=val></parent-expression>');
|
| - zone.run(() =>
|
| - $compile(element, directives)(injector, element));
|
| + it('should behave nicely if a mapped attribute evals to null', async((VmTurnZone zone) {
|
| + _.rootScope.context['val'] = null;
|
| + var element = _.compile('<parent-expression fromParent=val></parent-expression>');
|
|
|
| microLeap();
|
| - expect(renderedText(element)).toEqual('inside ');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('inside ');
|
| + }));
|
|
|
| - it('should create a component with I/O', async(inject(() {
|
| - var element = $(r'<div><io attr="A" expr="name" ondone="done=true"></io></div>');
|
| - $compile(element, directives)(injector, element);
|
| + it('should create a component with I/O', async(() {
|
| + _.compile(r'<div><io attr="A" expr="name" ondone="done=true"></io></div>');
|
| microLeap();
|
|
|
| - rootScope.context['name'] = 'misko';
|
| - rootScope.apply();
|
| - var component = rootScope.context['ioComponent'];
|
| + _.rootScope.context['name'] = 'misko';
|
| + _.rootScope.apply();
|
| + var component = _.rootScope.context['ioComponent'];
|
| expect(component.scope.context['name']).toEqual(null);
|
| expect(component.scope.context['attr']).toEqual('A');
|
| expect(component.scope.context['expr']).toEqual('misko');
|
| component.scope.context['expr'] = 'angular';
|
| - rootScope.apply();
|
| - expect(rootScope.context['name']).toEqual('angular');
|
| - expect(rootScope.context['done']).toEqual(null);
|
| + _.rootScope.apply();
|
| + expect(_.rootScope.context['name']).toEqual('angular');
|
| + expect(_.rootScope.context['done']).toEqual(null);
|
| component.scope.context['ondone']();
|
| - expect(rootScope.context['done']).toEqual(true);
|
| - })));
|
| + expect(_.rootScope.context['done']).toEqual(true);
|
| + }));
|
|
|
| - xit('should should not create any watchers if no attributes are specified', async(inject((Profiler perf) {
|
| - var element = $(r'<div><io></io></div>');
|
| - $compile(element, directives)(injector, element);
|
| + xit('should should not create any watchers if no attributes are specified', async((Profiler perf) {
|
| + _.compile(r'<div><io></io></div>');
|
| microLeap();
|
| - injector.get(Scope).apply();
|
| + _.injector.get(Scope).apply();
|
| // Re-enable once we can publish these numbers
|
| - //expect(rootScope.watchGroup.totalFieldCost).toEqual(0);
|
| - //expect(rootScope.watchGroup.totalCollectionCost).toEqual(0);
|
| - //expect(rootScope.watchGroup.totalEvalCost).toEqual(0);
|
| - //expect(rootScope.observeGroup.totalFieldCost).toEqual(0);
|
| - //expect(rootScope.observeGroup.totalCollectionCost).toEqual(0);
|
| - //expect(rootScope.observeGroup.totalEvalCost).toEqual(0);
|
| - })));
|
| -
|
| - it('should create a component with I/O and "=" binding value should be available', async(inject(() {
|
| - rootScope.context['name'] = 'misko';
|
| - var element = $(r'<div><io attr="A" expr="name" ondone="done=true"></io></div>');
|
| - $compile(element, directives)(injector, element);
|
| + //expect(_.rootScope.watchGroup.totalFieldCost).toEqual(0);
|
| + //expect(_.rootScope.watchGroup.totalCollectionCost).toEqual(0);
|
| + //expect(_.rootScope.watchGroup.totalEvalCost).toEqual(0);
|
| + //expect(_.rootScope.observeGroup.totalFieldCost).toEqual(0);
|
| + //expect(_.rootScope.observeGroup.totalCollectionCost).toEqual(0);
|
| + //expect(_.rootScope.observeGroup.totalEvalCost).toEqual(0);
|
| + }));
|
| +
|
| + it('should create a component with I/O and "=" binding value should be available', async(() {
|
| + _.rootScope.context['name'] = 'misko';
|
| + _.compile(r'<div><io attr="A" expr="name" ondone="done=true"></io></div>');
|
| microLeap();
|
|
|
| - var component = rootScope.context['ioComponent'];
|
| - rootScope.apply();
|
| + var component = _.rootScope.context['ioComponent'];
|
| + _.rootScope.apply();
|
| expect(component.scope.context['expr']).toEqual('misko');
|
| component.scope.context['expr'] = 'angular';
|
| - rootScope.apply();
|
| - expect(rootScope.context['name']).toEqual('angular');
|
| - })));
|
| -
|
| - it('should create a component with I/O bound to controller and "=" binding value should be available', async(inject(() {
|
| - rootScope.context['done'] = false;
|
| - var element = $(r'<div><io-controller attr="A" expr="name" once="name" ondone="done=true"></io-controller></div>');
|
| + _.rootScope.apply();
|
| + expect(_.rootScope.context['name']).toEqual('angular');
|
| + }));
|
|
|
| + it('should create a component with I/O bound to controller and "=" binding value should be available', async(() {
|
| + _.rootScope.context['done'] = false;
|
| + _.compile(r'<div><io-controller attr="A" expr="name" once="name" ondone="done=true"></io-controller></div>');
|
|
|
| - expect(injector).toBeDefined();
|
| - $compile(element, directives)(injector, element);
|
| + expect(_.injector).toBeDefined();
|
| microLeap();
|
|
|
| - IoControllerComponent component = rootScope.context['ioComponent'];
|
| + IoControllerComponent component = _.rootScope.context['ioComponent'];
|
|
|
| expect(component.expr).toEqual(null);
|
| expect(component.exprOnce).toEqual(null);
|
| expect(component.attr).toEqual('A');
|
| - rootScope.apply();
|
| + _.rootScope.apply();
|
|
|
| - rootScope.context['name'] = 'misko';
|
| - rootScope.apply();
|
| + _.rootScope.context['name'] = 'misko';
|
| + _.rootScope.apply();
|
| expect(component.expr).toEqual('misko');
|
| expect(component.exprOnce).toEqual('misko');
|
|
|
| - rootScope.context['name'] = 'igor';
|
| - rootScope.apply();
|
| + _.rootScope.context['name'] = 'igor';
|
| + _.rootScope.apply();
|
| expect(component.expr).toEqual('igor');
|
| expect(component.exprOnce).toEqual('misko');
|
|
|
| component.expr = 'angular';
|
| - rootScope.apply();
|
| - expect(rootScope.context['name']).toEqual('angular');
|
| + _.rootScope.apply();
|
| + expect(_.rootScope.context['name']).toEqual('angular');
|
|
|
| - expect(rootScope.context['done']).toEqual(false);
|
| + expect(_.rootScope.context['done']).toEqual(false);
|
| component.onDone();
|
| - expect(rootScope.context['done']).toEqual(true);
|
| + expect(_.rootScope.context['done']).toEqual(true);
|
|
|
| // Should be noop
|
| component.onOptional();
|
| - })));
|
| + }));
|
|
|
| - it('should create a map attribute to controller', async(inject(() {
|
| - var element = $(r'<div><io-controller attr="{{name}}"></io-controller></div>');
|
| - $compile(element, directives)(injector, element);
|
| + it('should create a map attribute to controller', async(() {
|
| + _.compile(r'<div><io-controller attr="{{name}}"></io-controller></div>');
|
| microLeap();
|
|
|
| - IoControllerComponent component = rootScope.context['ioComponent'];
|
| + IoControllerComponent component = _.rootScope.context['ioComponent'];
|
|
|
| - rootScope.context['name'] = 'misko';
|
| - rootScope.apply();
|
| + _.rootScope.context['name'] = 'misko';
|
| + _.rootScope.apply();
|
| expect(component.attr).toEqual('misko');
|
|
|
| - rootScope.context['name'] = 'james';
|
| - rootScope.apply();
|
| + _.rootScope.context['name'] = 'james';
|
| + _.rootScope.apply();
|
| expect(component.attr).toEqual('james');
|
| - })));
|
| + }));
|
|
|
| - it('should create a unpublished component with I/O bound to controller and "=" binding value should be available', async(inject(() {
|
| - rootScope.context['name'] = 'misko';
|
| - rootScope.context['done'] = false;
|
| - var element = $(r'<div><unpublished-io-controller attr="A" expr="name" ondone="done=true"></unpublished-io-controller></div>');
|
| - $compile(element, directives)(injector, element);
|
| + it('should create a unpublished component with I/O bound to controller and "=" binding value should be available', async(() {
|
| + _.rootScope.context['name'] = 'misko';
|
| + _.rootScope.context['done'] = false;
|
| + _.compile(r'<div><unpublished-io-controller attr="A" expr="name" ondone="done=true"></unpublished-io-controller></div>');
|
| microLeap();
|
|
|
| - UnpublishedIoControllerComponent component = rootScope.context['ioComponent'];
|
| - rootScope.apply();
|
| + UnpublishedIoControllerComponent component = _.rootScope.context['ioComponent'];
|
| + _.rootScope.apply();
|
| expect(component.attr).toEqual('A');
|
| expect(component.expr).toEqual('misko');
|
| component.expr = 'angular';
|
| - rootScope.apply();
|
| - expect(rootScope.context['name']).toEqual('angular');
|
| + _.rootScope.apply();
|
| + expect(_.rootScope.context['name']).toEqual('angular');
|
|
|
| - expect(rootScope.context['done']).toEqual(false);
|
| + expect(_.rootScope.context['done']).toEqual(false);
|
| component.onDone();
|
| - expect(rootScope.context['done']).toEqual(true);
|
| + expect(_.rootScope.context['done']).toEqual(true);
|
|
|
| // Should be noop
|
| component.onOptional();
|
| - })));
|
| + }));
|
|
|
| - it('should error on incorrect mapping', async(inject(() {
|
| + it('should error on incorrect mapping', async(() {
|
| expect(() {
|
| - var element = $(r'<div><incorrect-mapping></incorrect-mapping</div>');
|
| - $compile(element, directives)(injector, element);
|
| + _.compile(r'<div><incorrect-mapping></incorrect-mapping</div>');
|
| }).toThrow("Unknown mapping 'foo\' for attribute 'attr'.");
|
| - })));
|
| + }));
|
|
|
| - it('should support filters in attribute expressions', async(inject(() {
|
| - var element = $(r'''<expr-attr-component expr="'Misko' | hello" one-way="'James' | hello" once="'Chirayu' | hello"></expr-attr-component>''');
|
| - $compile(element, directives)(injector, element);
|
| - ExprAttrComponent component = rootScope.context['exprAttrComponent'];
|
| - rootScope.apply();
|
| + it('should support formatters in attribute expressions', async(() {
|
| + _.compile(r'''<expr-attr-component expr="'Misko' | hello" one-way="'James' | hello" once="'Chirayu' | hello"></expr-attr-component>''');
|
| + ExprAttrComponent component = _.rootScope.context['exprAttrComponent'];
|
| + _.rootScope.apply();
|
| expect(component.expr).toEqual('Hello, Misko!');
|
| expect(component.oneWay).toEqual('Hello, James!');
|
| expect(component.exprOnce).toEqual('Hello, Chirayu!');
|
| - })));
|
| + }));
|
|
|
| - it('should error on non-asignable-mapping', async(inject(() {
|
| + it('should error on non-asignable-mapping', async(() {
|
| expect(() {
|
| - var element = $(r'<div><non-assignable-mapping></non-assignable-mapping</div>');
|
| - $compile(element, directives)(injector, element);
|
| + _.compile(r'<div><non-assignable-mapping></non-assignable-mapping</div>');
|
| }).toThrow("Expression '1+2' is not assignable in mapping '@1+2' for attribute 'attr'.");
|
| - })));
|
| + }));
|
|
|
| - it('should expose mapped attributes as camel case', async(inject(() {
|
| - var element = $('<camel-case-map camel-case=G></camel-case-map>');
|
| - $compile(element, directives)(injector, element);
|
| + it('should expose mapped attributes as camel case', async(() {
|
| + _.compile('<camel-case-map camel-case=G></camel-case-map>');
|
| microLeap();
|
| - rootScope.apply();
|
| - var componentScope = rootScope.context['camelCase'];
|
| + _.rootScope.apply();
|
| + var componentScope = _.rootScope.context['camelCase'];
|
| expect(componentScope.context['camelCase']).toEqual('G');
|
| - })));
|
| + }));
|
|
|
| - it('should throw an exception if required directive is missing', async(inject((Compiler $compile, Scope rootScope, Injector injector) {
|
| + // TODO: This is a terrible test
|
| + it('should throw an exception if required directive is missing', async(() {
|
| try {
|
| - var element = $('<tab local><pane></pane><pane local></pane></tab>');
|
| - $compile(element, directives)(injector, element);
|
| + _.compile('<tab local><pane></pane><pane local></pane></tab>');
|
| } catch (e) {
|
| var text = '$e';
|
| expect(text).toContain('No provider found for');
|
| expect(text).toContain('(resolving ');
|
| expect(text).toContain('LocalAttrDirective');
|
| }
|
| - })));
|
| -
|
| - it('should publish component controller into the scope', async(inject((NgZone zone) {
|
| - var element = $(r'<div><publish-me></publish-me></div>');
|
| - zone.run(() =>
|
| - $compile(element, directives)(injector, element));
|
| + }));
|
|
|
| + it('should publish component controller into the scope', async(() {
|
| + var element = _.compile(r'<div><publish-me></publish-me></div>');
|
| microLeap();
|
| - expect(element.textWithShadow()).toEqual('WORKED');
|
| - })));
|
| + _.rootScope.apply();
|
| + expect(element).toHaveText('WORKED');
|
| + }));
|
|
|
| - it('should publish directive controller into the scope', async(inject((NgZone zone) {
|
| - var element = $(r'<div><div publish-me>{{ctrlName.value}}</div></div>');
|
| - zone.run(() =>
|
| - $compile(element, directives)(injector, element));
|
| + it('should publish directive controller into the scope', async((VmTurnZone zone) {
|
| + var element = _.compile(r'<div><div publish-me>{{ctrlName.value}}</div></div>');
|
|
|
| microLeap();
|
| - expect(element.text()).toEqual('WORKED');
|
| - })));
|
| -
|
| - it('should "publish" controller to injector under provided publishTypes', inject(() {
|
| - var element = $(r'<div publish-types></div>');
|
| - $compile(element, directives)(injector, element);
|
| - expect(PublishTypesAttrDirective._injector.get(PublishTypesAttrDirective)).
|
| - toBe(PublishTypesAttrDirective._injector.get(PublishTypesDirectiveSuperType));
|
| + _.rootScope.apply();
|
| + expect(element.text).toEqual('WORKED');
|
| }));
|
|
|
| - it('should allow repeaters over controllers', async(inject((Logger logger) {
|
| - var element = $(r'<log ng-repeat="i in [1, 2]"></log>');
|
| - $compile(element, directives)(injector, element);
|
| - rootScope.apply();
|
| + it('should "publish" controller to injector under provided module', () {
|
| + _.compile(r'<div publish-types></div>');
|
| + expect(PublishModuleAttrDirective._injector.get(PublishModuleAttrDirective)).
|
| + toBe(PublishModuleAttrDirective._injector.get(PublishModuleDirectiveSuperType));
|
| + });
|
| +
|
| + it('should allow repeaters over controllers', async((Logger logger) {
|
| + _.compile(r'<log ng-repeat="i in [1, 2]"></log>');
|
| + _.rootScope.apply();
|
| microLeap();
|
|
|
| expect(logger.length).toEqual(2);
|
| - })));
|
| + }));
|
|
|
| describe('lifecycle', () {
|
| - var backend;
|
| - beforeEach(module((Module module) {
|
| - backend = new MockHttpBackend();
|
| + beforeEachModule((Module module) {
|
| + var httpBackend = new MockHttpBackend();
|
| +
|
| module
|
| - ..value(HttpBackend, backend)
|
| - ..value(MockHttpBackend, backend);
|
| - }));
|
| + ..value(HttpBackend, httpBackend)
|
| + ..value(MockHttpBackend, httpBackend);
|
| + });
|
|
|
| - it('should fire onTemplate method', async(inject((Logger logger, MockHttpBackend backend) {
|
| - backend.whenGET('some/template.url').respond('<div>WORKED</div>');
|
| - var scope = rootScope.createChild({});
|
| + it('should fire onShadowRoot method', async((Compiler compile, Logger logger, MockHttpBackend backend) {
|
| + backend.whenGET('some/template.url').respond(200, '<div>WORKED</div>');
|
| + var scope = _.rootScope.createChild({});
|
| scope.context['isReady'] = 'ready';
|
| scope.context['logger'] = logger;
|
| scope.context['once'] = null;
|
| - var element = $('<attach-detach attr-value="{{isReady}}" expr-value="isReady" once-value="once">{{logger("inner")}}</attach-detach>');
|
| - $compile(element, directives)(injector.createChild([new Module()..value(Scope, scope)]), element);
|
| + var elts = es('<attach-detach attr-value="{{isReady}}" expr-value="isReady" once-value="once">{{logger("inner")}}</attach-detach>');
|
| + compile(elts, _.injector.get(DirectiveMap))(_.injector.createChild([new Module()..value(Scope, scope)]), elts);
|
| expect(logger).toEqual(['new']);
|
|
|
| expect(logger).toEqual(['new']);
|
|
|
| - rootScope.apply();
|
| + _.rootScope.apply();
|
| var expected = ['new', 'attach:@ready; =>ready; =>!null', 'inner'];
|
| assert((() {
|
| // there is an assertion in flush which double checks that
|
| @@ -476,119 +558,180 @@ main() => describe('dte.compiler', () {
|
| expect(logger).toEqual(expected);
|
| logger.clear();
|
|
|
| + microLeap();
|
| backend.flush();
|
| microLeap();
|
| - expect(logger).toEqual(['templateLoaded', rootScope.context['shadowRoot']]);
|
| + expect(logger).toEqual(['templateLoaded', _.rootScope.context['shadowRoot']]);
|
| logger.clear();
|
|
|
| scope.destroy();
|
| expect(logger).toEqual(['detach']);
|
| - expect(element.textWithShadow()).toEqual('WORKED');
|
| - })));
|
| + expect(elts).toHaveText('WORKED');
|
| + }));
|
|
|
| - it('should should not call attach after scope is destroyed', async(inject((Logger logger, MockHttpBackend backend) {
|
| + it('should should not call attach after scope is destroyed', async((Compiler compile, Logger logger, MockHttpBackend backend) {
|
| backend.whenGET('foo.html').respond('<div>WORKED</div>');
|
| - var element = $('<simple-attach></simple-attach>');
|
| - var scope = rootScope.createChild({});
|
| - $compile(element, directives)(injector.createChild([new Module()..value(Scope, scope)]), element);
|
| + var elts = es('<simple-attach></simple-attach>');
|
| + var scope = _.rootScope.createChild({});
|
| + compile(elts, _.injector.get(DirectiveMap))(_.injector.createChild([new Module()..value(Scope, scope)]), elts);
|
| expect(logger).toEqual(['SimpleAttachComponent']);
|
| scope.destroy();
|
|
|
| - rootScope.apply();
|
| + _.rootScope.apply();
|
| microLeap();
|
|
|
| expect(logger).toEqual(['SimpleAttachComponent']);
|
| - })));
|
| + }));
|
| +
|
| + it('should inject compenent element as the dom.Element', async((Logger log, TestBed _, MockHttpBackend backend) {
|
| + backend.whenGET('foo.html').respond('<div>WORKED</div>');
|
| + _.compile('<log-element></log-element>');
|
| + Element element = _.rootElement;
|
| + expect(log).toEqual([element, element,
|
| + // If we don't have a shadowRoot, this is an invalid check
|
| + element.shadowRoot != null ? element.shadowRoot : log[2]]);
|
| + }));
|
| });
|
|
|
| describe('invalid components', () {
|
| it('should throw a useful error message for missing selectors', () {
|
| - module((Module module) {
|
| - module
|
| + Module module = new Module()
|
| ..type(MissingSelector);
|
| - });
|
| + var injector = _.injector.createChild([module], forceNewInstances: [Compiler, DirectiveMap]);
|
| + var c = injector.get(Compiler);
|
| + var directives = injector.get(DirectiveMap);
|
| expect(() {
|
| - inject((Compiler c) { });
|
| + c(es('<div></div>'), injector.get(DirectiveMap));
|
| }).toThrow('Missing selector annotation for MissingSelector');
|
| });
|
|
|
|
|
| it('should throw a useful error message for invalid selector', () {
|
| - module((Module module) {
|
| - module
|
| - ..type(InvalidSelector);
|
| - });
|
| + Module module = new Module()
|
| + ..type(InvalidSelector);
|
| + var injector = _.injector.createChild([module], forceNewInstances: [Compiler, DirectiveMap]);
|
| + var c = injector.get(Compiler);
|
| + var directives = injector.get(DirectiveMap);
|
| +
|
| expect(() {
|
| - inject((Compiler c) { });
|
| + c(es('<div></div>'), directives);
|
| }).toThrow('Unknown selector format \'buttonbar button\' for InvalidSelector');
|
| });
|
| });
|
| +
|
| + describe('useShadowDom option', () {
|
| + beforeEachModule((Module m) {
|
| + m.type(ShadowyComponent);
|
| + m.type(ShadowlessComponent);
|
| + });
|
| +
|
| + it('should create shadowy components', async((Logger log) {
|
| + _.compile('<shadowy></shadowy>');
|
| + expect(log).toEqual(['shadowy']);
|
| + expect(_.rootElement.shadowRoot).toBeNotNull();
|
| + }));
|
| +
|
| + it('should create shadowless components', async((Logger log) {
|
| + _.compile('<shadowless></shadowless>');
|
| + expect(log).toEqual(['shadowless']);
|
| + expect(_.rootElement.shadowRoot).toBeNull();
|
| + }));
|
| +
|
| + it('should create other components with the default strategy', async((ComponentFactory factory) {
|
| + _.compile('<simple></simple>');
|
| + if (factory is TranscludingComponentFactory) {
|
| + expect(_.rootElement.shadowRoot).toBeNull();
|
| + } else {
|
| + expect(factory is ShadowDomComponentFactory).toBeTruthy();
|
| + expect(_.rootElement.shadowRoot).toBeNotNull();
|
| + }
|
| + }));
|
| + });
|
| });
|
|
|
|
|
| describe('controller scoping', () {
|
| - it('should make controllers available to sibling and child controllers', async(inject((Compiler $compile, Scope rootScope, Logger log, Injector injector) {
|
| - var element = $('<tab local><pane local></pane><pane local></pane></tab>');
|
| - $compile(element, directives)(injector, element);
|
| + it('should make controllers available to sibling and child controllers', async((Logger log) {
|
| + _.compile('<tab local><pane local></pane><pane local></pane></tab>');
|
| microLeap();
|
|
|
| expect(log.result()).toEqual('TabComponent-0; LocalAttrDirective-0; PaneComponent-1; LocalAttrDirective-0; PaneComponent-2; LocalAttrDirective-0');
|
| - })));
|
| + }));
|
| +
|
| + it('should use the correct parent injector', async((Logger log) {
|
| + // Getting the parent offsets correct while descending the template is tricky. If we get it wrong, this
|
| + // test case will create too many TabComponents.
|
|
|
| - it('should reuse controllers for transclusions', async(inject((Compiler $compile, Scope rootScope, Logger log, Injector injector) {
|
| - var element = $('<div simple-transclude-in-attach include-transclude>block</div>');
|
| - $compile(element, directives)(injector, element);
|
| + _.compile('<div ng-bind="true"><div ignore-children></div><tab local><pane local></pane></tab>');
|
| microLeap();
|
|
|
| - rootScope.apply();
|
| + expect(log.result()).toEqual('Ignore; TabComponent-0; LocalAttrDirective-0; PaneComponent-1; LocalAttrDirective-0');
|
| + }));
|
| +
|
| + it('should reuse controllers for transclusions', async((Logger log) {
|
| + _.compile('<div simple-transclude-in-attach include-transclude>view</div>');
|
| + microLeap();
|
| +
|
| + _.rootScope.apply();
|
| expect(log.result()).toEqual('IncludeTransclude; SimpleTransclude');
|
| - })));
|
| + }));
|
|
|
| - it('should expose a parent controller to the scope of its children', inject((TestBed _) {
|
| + it('should expose a parent controller to the scope of its children', (TestBed _) {
|
| + var element = _.compile('<div my-parent-controller>'
|
| + ' <div my-child-controller>{{ my_parent.data() }}</div>'
|
| + '</div>');
|
|
|
| - var element = _.compile('<div my-parent-controller>' +
|
| - ' <div my-child-controller>{{ my_parent.data() }}</div>' +
|
| - '</div>');
|
| + _.rootScope.apply();
|
| +
|
| + expect(element.text).toContain('my data');
|
| + });
|
|
|
| - rootScope.apply();
|
| + it('should expose a ancestor controller to the scope of its children thru a undecorated element', (TestBed _) {
|
| + var element = _.compile(
|
| + '<div my-parent-controller>'
|
| + '<div>'
|
| + '<div my-child-controller>{{ my_parent.data() }}</div>'
|
| + '</div>'
|
| + '</div>');
|
| +
|
| + _.rootScope.apply();
|
|
|
| expect(element.text).toContain('my data');
|
| - }));
|
| + });
|
| });
|
|
|
|
|
| - describe('NgDirective', () {
|
| - it('should allow creation of a new scope', inject((TestBed _) {
|
| + describe('Decorator', () {
|
| + it('should allow creation of a new scope', () {
|
| _.rootScope.context['name'] = 'cover me';
|
| _.compile('<div><div my-controller>{{name}}</div></div>');
|
| _.rootScope.apply();
|
| expect(_.rootScope.context['name']).toEqual('cover me');
|
| expect(_.rootElement.text).toEqual('MyController');
|
| - }));
|
| + });
|
| });
|
|
|
| - });
|
| + }));
|
| +}
|
|
|
|
|
| -@NgController(
|
| +@Controller(
|
| selector: '[my-parent-controller]',
|
| - publishAs: 'my_parent'
|
| -)
|
| + publishAs: 'my_parent')
|
| class MyParentController {
|
| data() {
|
| return "my data";
|
| }
|
| }
|
|
|
| -@NgController(
|
| +@Controller(
|
| selector: '[my-child-controller]',
|
| - publishAs: 'my_child'
|
| -)
|
| + publishAs: 'my_child')
|
| class MyChildController {}
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'tab',
|
| - visibility: NgDirective.DIRECT_CHILDREN_VISIBILITY)
|
| + visibility: Directive.DIRECT_CHILDREN_VISIBILITY)
|
| class TabComponent {
|
| int id = 0;
|
| Logger log;
|
| @@ -599,7 +742,7 @@ class TabComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(selector: 'pane')
|
| +@Component(selector: 'pane')
|
| class PaneComponent {
|
| TabComponent tabComponent;
|
| LocalAttrDirective localDirective;
|
| @@ -610,9 +753,9 @@ class PaneComponent {
|
| }
|
| }
|
|
|
| -@NgDirective(
|
| +@Decorator(
|
| selector: '[local]',
|
| - visibility: NgDirective.LOCAL_VISIBILITY)
|
| + visibility: Directive.LOCAL_VISIBILITY)
|
| class LocalAttrDirective {
|
| int id = 0;
|
| Logger log;
|
| @@ -622,72 +765,116 @@ class LocalAttrDirective {
|
| }
|
| }
|
|
|
| -@NgDirective(
|
| +@Decorator(
|
| selector: '[simple-transclude-in-attach]',
|
| - visibility: NgDirective.CHILDREN_VISIBILITY, children: NgAnnotation.TRANSCLUDE_CHILDREN)
|
| + visibility: Directive.CHILDREN_VISIBILITY, children: Directive.TRANSCLUDE_CHILDREN)
|
| class SimpleTranscludeInAttachAttrDirective {
|
| - SimpleTranscludeInAttachAttrDirective(BlockHole blockHole, BoundBlockFactory boundBlockFactory, Logger log, RootScope scope) {
|
| + SimpleTranscludeInAttachAttrDirective(ViewPort viewPort, BoundViewFactory boundViewFactory, Logger log, RootScope scope) {
|
| scope.runAsync(() {
|
| - var block = boundBlockFactory(scope);
|
| - block.insertAfter(blockHole);
|
| + var view = boundViewFactory(scope);
|
| + viewPort.insert(view);
|
| log('SimpleTransclude');
|
| });
|
| }
|
| }
|
|
|
| -@NgDirective(selector: '[include-transclude]')
|
| +@Decorator(selector: '[include-transclude]')
|
| class IncludeTranscludeAttrDirective {
|
| IncludeTranscludeAttrDirective(SimpleTranscludeInAttachAttrDirective simple, Logger log) {
|
| log('IncludeTransclude');
|
| }
|
| }
|
|
|
| -@NgDirective(selector: '[two-directives]')
|
| +@Decorator(selector: '[two-directives]')
|
| class OneOfTwoDirectives {
|
| OneOfTwoDirectives(Logger log) {
|
| log('OneOfTwo');
|
| }
|
| }
|
|
|
| -@NgDirective(selector: '[two-directives]')
|
| +@Decorator(selector: '[two-directives]')
|
| class TwoOfTwoDirectives {
|
| TwoOfTwoDirectives(Logger log) {
|
| log('TwoOfTwo');
|
| }
|
| }
|
|
|
| -class PublishTypesDirectiveSuperType {
|
| +@Decorator(
|
| + selector: '[ignore-children]',
|
| + children: Directive.IGNORE_CHILDREN
|
| +)
|
| +class IgnoreChildrenDirective {
|
| + IgnoreChildrenDirective(Logger log) {
|
| + log('Ignore');
|
| + }
|
| }
|
|
|
| -@NgDirective(
|
| +class PublishModuleDirectiveSuperType {
|
| +}
|
| +
|
| +@Decorator(
|
| selector: '[publish-types]',
|
| - publishTypes: const [PublishTypesDirectiveSuperType])
|
| -class PublishTypesAttrDirective implements PublishTypesDirectiveSuperType {
|
| + module: PublishModuleAttrDirective.module)
|
| +class PublishModuleAttrDirective implements PublishModuleDirectiveSuperType {
|
| + static Module _module = new Module()
|
| + ..factory(PublishModuleDirectiveSuperType, (i) => i.get(PublishModuleAttrDirective));
|
| + static module() => _module;
|
| +
|
| static Injector _injector;
|
| - PublishTypesAttrDirective(Injector injector) {
|
| + PublishModuleAttrDirective(Injector injector) {
|
| _injector = injector;
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'simple',
|
| - template: r'{{name}}(<content>SHADOW-CONTENT</content>)'
|
| -)
|
| + template: r'{{name}}(<content>SHADOW-CONTENT</content>)')
|
| class SimpleComponent {
|
| - SimpleComponent(Scope scope) {
|
| + Scope scope;
|
| + SimpleComponent(Scope this.scope) {
|
| scope.context['name'] = 'INNER';
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| + selector: 'shadowy',
|
| + template: r'With shadow DOM',
|
| + useShadowDom: true
|
| +)
|
| +class ShadowyComponent {
|
| + ShadowyComponent(Logger log) {
|
| + log('shadowy');
|
| + }
|
| +}
|
| +
|
| +@Component(
|
| + selector: 'shadowless',
|
| + template: r'Without shadow DOM',
|
| + useShadowDom: false
|
| +)
|
| +class ShadowlessComponent {
|
| + ShadowlessComponent(Logger log) {
|
| + log('shadowless');
|
| + }
|
| +}
|
| +
|
| +@Component(
|
| + selector: 'sometimes',
|
| + template: r'<div ng-if="ctrl.sometimes"><content></content></div>',
|
| + publishAs: 'ctrl')
|
| +class SometimesComponent {
|
| + @NgTwoWay('sometimes')
|
| + var sometimes;
|
| +}
|
| +
|
| +@Component(
|
| selector: 'io',
|
| template: r'<content></content>',
|
| map: const {
|
| 'attr': '@scope.context.attr',
|
| 'expr': '<=>scope.context.expr',
|
| 'ondone': '&scope.context.ondone',
|
| - }
|
| -)
|
| + })
|
| class IoComponent {
|
| Scope scope;
|
| IoComponent(Scope scope) {
|
| @@ -697,7 +884,7 @@ class IoComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'io-controller',
|
| template: r'<content></content>',
|
| publishAs: 'ctrl',
|
| @@ -707,8 +894,7 @@ class IoComponent {
|
| 'once': '=>!exprOnce',
|
| 'ondone': '&onDone',
|
| 'on-optional': '&onOptional'
|
| - }
|
| -)
|
| + })
|
| class IoControllerComponent {
|
| Scope scope;
|
| var attr;
|
| @@ -722,7 +908,7 @@ class IoControllerComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'unpublished-io-controller',
|
| template: r'<content></content>',
|
| map: const {
|
| @@ -730,8 +916,7 @@ class IoControllerComponent {
|
| 'expr': '<=>expr',
|
| 'ondone': '&onDone',
|
| 'onOptional': '&onOptional'
|
| - }
|
| -)
|
| + })
|
| class UnpublishedIoControllerComponent {
|
| Scope scope;
|
| var attr;
|
| @@ -745,24 +930,23 @@ class UnpublishedIoControllerComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'incorrect-mapping',
|
| template: r'<content></content>',
|
| map: const { 'attr': 'foo' })
|
| class IncorrectMappingComponent { }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'non-assignable-mapping',
|
| template: r'<content></content>',
|
| map: const { 'attr': '@1+2' })
|
| class NonAssignableMappingComponent { }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'camel-case-map',
|
| map: const {
|
| 'camel-case': '@scope.context.camelCase',
|
| - }
|
| -)
|
| + })
|
| class CamelCaseMapComponent {
|
| Scope scope;
|
| CamelCaseMapComponent(Scope this.scope) {
|
| @@ -770,49 +954,44 @@ class CamelCaseMapComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'parent-expression',
|
| template: '<div>inside {{fromParent()}}</div>',
|
| map: const {
|
| 'from-parent': '&scope.context.fromParent',
|
| - }
|
| -)
|
| + })
|
| class ParentExpressionComponent {
|
| Scope scope;
|
| ParentExpressionComponent(Scope this.scope);
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'publish-me',
|
| - template: r'<content>{{ctrlName.value}}</content>',
|
| - publishAs: 'ctrlName'
|
| -)
|
| + template: r'{{ctrlName.value}}',
|
| + publishAs: 'ctrlName')
|
| class PublishMeComponent {
|
| String value = 'WORKED';
|
| }
|
|
|
| -
|
| -@NgController (
|
| +@Controller (
|
| selector: '[publish-me]',
|
| - publishAs: 'ctrlName'
|
| -)
|
| + publishAs: 'ctrlName')
|
| class PublishMeDirective {
|
| String value = 'WORKED';
|
| }
|
|
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'log',
|
| template: r'<content></content>',
|
| - publishAs: 'ctrlName'
|
| -)
|
| + publishAs: 'ctrlName')
|
| class LogComponent {
|
| LogComponent(Scope scope, Logger logger) {
|
| logger(scope);
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'attach-detach',
|
| templateUrl: 'some/template.url',
|
| map: const {
|
| @@ -822,9 +1001,8 @@ class LogComponent {
|
| 'optional-one': '=>optional',
|
| 'optional-two': '<=>optional',
|
| 'optional-once': '=>!optional',
|
| - }
|
| -)
|
| -class AttachDetachComponent implements NgAttachAware, NgDetachAware, NgShadowRootAware {
|
| + })
|
| +class AttachDetachComponent implements AttachAware, DetachAware, ShadowRootAware {
|
| Logger logger;
|
| Scope scope;
|
| String attrValue = 'too early';
|
| @@ -845,30 +1023,29 @@ class AttachDetachComponent implements NgAttachAware, NgDetachAware, NgShadowRoo
|
| }
|
| }
|
|
|
| -@NgController(
|
| +@Controller(
|
| selector: '[my-controller]',
|
| - publishAs: 'myCtrl'
|
| -)
|
| + publishAs: 'myCtrl')
|
| class MyController {
|
| MyController(Scope scope) {
|
| scope.context['name'] = 'MyController';
|
| }
|
| }
|
|
|
| -@NgComponent()
|
| +@Component()
|
| class MissingSelector {}
|
|
|
| -@NgComponent(selector: 'buttonbar button')
|
| +@Component(selector: 'buttonbar button')
|
| class InvalidSelector {}
|
|
|
| -@NgFilter(name:'hello')
|
| +@Formatter(name:'hello')
|
| class SayHelloFilter {
|
| call(String str) {
|
| return 'Hello, $str!';
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'expr-attr-component',
|
| template: r'<content></content>',
|
| publishAs: 'ctrl',
|
| @@ -876,8 +1053,7 @@ class SayHelloFilter {
|
| 'expr': '<=>expr',
|
| 'one-way': '=>oneWay',
|
| 'once': '=>!exprOnce'
|
| - }
|
| -)
|
| + })
|
| class ExprAttrComponent {
|
| var expr;
|
| var oneWay;
|
| @@ -888,10 +1064,10 @@ class ExprAttrComponent {
|
| }
|
| }
|
|
|
| -@NgComponent(
|
| +@Component(
|
| selector: 'simple-attach',
|
| templateUrl: 'foo.html')
|
| -class SimpleAttachComponent implements NgAttachAware, NgShadowRootAware {
|
| +class SimpleAttachComponent implements AttachAware, ShadowRootAware {
|
| Logger logger;
|
| SimpleAttachComponent(this.logger) {
|
| logger('SimpleAttachComponent');
|
| @@ -899,3 +1075,15 @@ class SimpleAttachComponent implements NgAttachAware, NgShadowRootAware {
|
| attach() => logger('attach');
|
| onShadowRoot(_) => logger('onShadowRoot');
|
| }
|
| +
|
| +@Component(
|
| + selector: 'log-element',
|
| + templateUrl: 'foo.html')
|
| +class LogElementComponent{
|
| + LogElementComponent(Logger logger, Element element, Node node,
|
| + ShadowRoot shadowRoot) {
|
| + logger(element);
|
| + logger(node);
|
| + logger(shadowRoot);
|
| + }
|
| +}
|
|
|