From 04c8a1f8301263f415f4ee6345b0cccf3ab31b03 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Tue, 3 May 2016 22:38:22 -0700 Subject: [PATCH] feat: update to @angular rc0 packages & latest CLI (#384) - Includes update to newest router - Completely rewrites checkbox tests --- .travis.yml | 1 + angular-cli-build.js | 17 +- angular-cli.json | 25 + package.json | 26 +- public/empty-placeholder | 0 src/components/button/button.spec.ts | 7 +- src/components/button/button.ts | 2 +- src/components/card/card.ts | 2 +- src/components/checkbox/checkbox.scss | 2 +- src/components/checkbox/checkbox.spec.ts | 1019 ++++++----------- src/components/checkbox/checkbox.ts | 33 +- src/components/grid-list/grid-list.ts | 2 +- src/components/icon/fake-svgs.ts | 2 +- src/components/icon/icon-registry.ts | 19 +- src/components/icon/icon.spec.ts | 10 +- src/components/icon/icon.ts | 11 +- src/components/input/input.spec.ts | 16 +- src/components/input/input.ts | 21 +- src/components/list/list.spec.ts | 8 +- src/components/list/list.ts | 15 +- .../progress-bar/progress-bar.spec.ts | 7 +- src/components/progress-bar/progress-bar.ts | 11 +- .../progress-circle/progress-circle.spec.ts | 7 +- .../progress-circle/progress-circle.ts | 2 +- src/components/radio/radio.spec.ts | 8 +- src/components/radio/radio.ts | 10 +- src/components/radio/radio_dispatcher.ts | 4 +- src/components/sidenav/sidenav.spec.ts | 19 +- src/components/sidenav/sidenav.ts | 45 +- src/components/toolbar/toolbar.spec.ts | 8 +- src/components/toolbar/toolbar.ts | 6 +- src/core/async/promise-completer.ts | 13 + src/core/gestures/MdGestureConfig.ts | 4 +- .../live-announcer/live-announcer.spec.ts | 15 +- src/core/live-announcer/live-announcer.ts | 2 +- src/core/overlay/overlay.spec.ts | 6 +- src/core/overlay/overlay.ts | 2 +- .../position/global-position-strategy.spec.ts | 2 +- .../position/relative-position-strategy.ts | 2 +- src/core/portal/dom-portal-host.ts | 13 +- src/core/portal/portal-directives.ts | 9 +- ...{portal-exceptions.ts => portal-errors.ts} | 17 +- src/core/portal/portal.spec.ts | 132 +-- src/core/portal/portal.ts | 41 +- src/core/rtl/dir.ts | 2 +- src/demo-app/button/button-demo.ts | 2 +- src/demo-app/card/card-demo.ts | 2 +- src/demo-app/checkbox/checkbox-demo.html | 4 + src/demo-app/checkbox/checkbox-demo.ts | 5 +- src/demo-app/demo-app.html | 32 +- src/demo-app/demo-app.ts | 40 +- src/demo-app/gestures/gestures-demo.ts | 2 +- src/demo-app/grid-list/grid-list-demo.ts | 2 +- src/demo-app/icon/icon-demo.ts | 2 +- src/demo-app/input/input-demo.ts | 2 +- src/demo-app/list/list-demo.ts | 2 +- .../live-announcer/live-announcer-demo.ts | 2 +- src/demo-app/overlay/overlay-demo.ts | 2 +- src/demo-app/portal/portal-demo.ts | 6 +- .../progress-bar/progress-bar-demo.ts | 2 +- .../progress-circle/progress-circle-demo.ts | 2 +- src/demo-app/radio/radio-demo.ts | 2 +- src/demo-app/sidenav/sidenav-demo.ts | 2 +- src/demo-app/toolbar/toolbar-demo.ts | 2 +- src/index.html | 34 +- src/main.ts | 12 +- src/system-config.ts | 66 ++ test/karma-test-shim.js | 126 +- test/karma.config.ts | 25 +- 69 files changed, 862 insertions(+), 1141 deletions(-) create mode 100644 angular-cli.json create mode 100644 public/empty-placeholder create mode 100644 src/core/async/promise-completer.ts rename src/core/portal/{portal-exceptions.ts => portal-errors.ts} (71%) create mode 100644 src/system-config.ts diff --git a/.travis.yml b/.travis.yml index 8866678cc2f7..35196cb09681 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,7 @@ matrix: allow_failures: - env: "MODE=saucelabs_optional" - env: "MODE=browserstack_optional" + - env: "MODE=e2e" install: - npm install diff --git a/angular-cli-build.js b/angular-cli-build.js index 92c173c48d8d..362ba6d06168 100644 --- a/angular-cli-build.js +++ b/angular-cli-build.js @@ -20,17 +20,24 @@ module.exports = function(defaults) { 'src/core/style' ] }, - vendorNpmFiles: [] + vendorNpmFiles: [ + 'systemjs/dist/system-polyfills.js', + 'systemjs/dist/system.src.js', + 'zone.js/dist/*.js', + 'es6-shim/es6-shim.js', + 'reflect-metadata/*.js', + 'rxjs/**/*.js', + '@angular/**/*.js', + ] }); - const ngTree = angularAppTree.toTree(); - const cssAutoprefixed = autoPrefixerTree(new Funnel(ngTree, { + const cssAutoprefixed = autoPrefixerTree(new Funnel(angularAppTree, { include: [ '**/*.css' ] })); return new MergeTree([ new Funnel('src', { include: ['**/*.scss']}), - angularAppTree.toTree(), - cssAutoprefixed + angularAppTree, + cssAutoprefixed, ], { overwrite: true }); }; diff --git a/angular-cli.json b/angular-cli.json new file mode 100644 index 000000000000..b416b34f14ee --- /dev/null +++ b/angular-cli.json @@ -0,0 +1,25 @@ +{ + "project": { + "version": "0.0.37", + "name": "material2" + }, + "apps": [ + {"main": "src/main.ts", "tsconfig": "src/tsconfig.json"} + ], + "addons": [], + "packages": [], + "e2e": { + "protractor": { + "config": "test/protractor.conf.js" + } + }, + "test": { + "karma": { + "config": "test/karma.conf.js" + } + }, + "defaults": { + "prefix": "", + "sourceDir": "src" + } +} diff --git a/package.json b/package.json index aebcb234be87..f536813c2cc8 100644 --- a/package.json +++ b/package.json @@ -25,45 +25,51 @@ "node": ">= 4.2.1 < 5" }, "dependencies": { - "angular2": "2.0.0-beta.17", + "@angular/common": "2.0.0-rc.0", + "@angular/compiler": "2.0.0-rc.0", + "@angular/core": "2.0.0-rc.0", + "@angular/router": "2.0.0-rc.0", + "@angular/http": "2.0.0-rc.0", + "@angular/platform-browser": "2.0.0-rc.0", + "@angular/platform-browser-dynamic": "2.0.0-rc.0", "es6-promise": "^3.0.2", "es6-shim": "^0.35.0", - "reflect-metadata": "0.1.2", + "reflect-metadata": "0.1.3", "rxjs": "5.0.0-beta.6", - "systemjs": "0.19.20", + "systemjs": "0.19.26", "zone.js": "0.6.12" }, "devDependencies": { "add-stream": "^1.0.0", - "angular-cli": "^0.0.31", + "angular-cli": "0.0.37", "broccoli-autoprefixer": "^4.1.0", "broccoli-funnel": "^1.0.1", "broccoli-merge-trees": "^1.1.1", "browserstacktunnel-wrapper": "^1.4.2", "conventional-changelog": "^1.1.0", - "ember-cli-inject-live-reload": "^1.3.0", + "ember-cli-inject-live-reload": "^1.4.0", "firebase-tools": "^2.2.1", "fs-extra": "^0.26.5", "glob": "^6.0.4", "gulp": "^3.9.1", "gulp-inline-ng2-template": "^1.1.2", - "jasmine-core": "^2.3.4", + "jasmine-core": "^2.4.1", "js-yaml": "^3.5.2", "karma": "^0.13.15", "karma-browserstack-launcher": "^0.1.7", - "karma-chrome-launcher": "^0.2.1", + "karma-chrome-launcher": "^0.2.3", "karma-firefox-launcher": "^0.1.7", - "karma-jasmine": "^0.3.6", + "karma-jasmine": "^0.3.8", "karma-sauce-launcher": "^0.2.14", "node-sass": "^3.4.2", - "protractor": "^3.1.1", + "protractor": "^3.3.0", "sass": "^0.5.0", "strip-ansi": "^3.0.0", "symlink-or-copy": "^1.0.1", "ts-node": "^0.5.5", "tslint": "^3.5.0", "typescript": "^1.8.0", - "typings": "^0.6.8", + "typings": "^0.8.1", "which": "^1.2.4" } } diff --git a/public/empty-placeholder b/public/empty-placeholder new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/components/button/button.spec.ts b/src/components/button/button.spec.ts index ffe5d3614463..8116e687600a 100644 --- a/src/components/button/button.spec.ts +++ b/src/components/button/button.spec.ts @@ -1,6 +1,7 @@ -import {it, describe, expect, beforeEach, inject, TestComponentBuilder} from 'angular2/testing'; -import {Component} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +import {it, describe, expect, beforeEach, inject} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdButton, MdAnchor} from './button'; diff --git a/src/components/button/button.ts b/src/components/button/button.ts index d63055cfb9c5..2e5127c2b942 100644 --- a/src/components/button/button.ts +++ b/src/components/button/button.ts @@ -6,7 +6,7 @@ import { ChangeDetectionStrategy, ElementRef, Renderer, -} from 'angular2/core'; +} from '@angular/core'; // TODO(jelbourn): Ink ripples. // TODO(jelbourn): Make the `isMouseDown` stuff done with one global listener. diff --git a/src/components/card/card.ts b/src/components/card/card.ts index 6127fbd9cfe4..69901a276477 100644 --- a/src/components/card/card.ts +++ b/src/components/card/card.ts @@ -1,4 +1,4 @@ -import {Component, ViewEncapsulation, ChangeDetectionStrategy} from 'angular2/core'; +import {Component, ViewEncapsulation, ChangeDetectionStrategy} from '@angular/core'; /* diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss index 9ce568fcb0a7..1ad59c831cae 100644 --- a/src/components/checkbox/checkbox.scss +++ b/src/components/checkbox/checkbox.scss @@ -216,7 +216,7 @@ $_md-checkbox-indeterminate-checked-easing-function: cubic-bezier(0.14, 0, 0, 1) pointer-events: none; } -.md-checkbox { +md-checkbox { cursor: pointer; &:focus { diff --git a/src/components/checkbox/checkbox.spec.ts b/src/components/checkbox/checkbox.spec.ts index 84a2fa126d45..05404886d01f 100644 --- a/src/components/checkbox/checkbox.spec.ts +++ b/src/components/checkbox/checkbox.spec.ts @@ -1,813 +1,502 @@ import { - it, - describe, - expect, - beforeEach, - fakeAsync, - inject, - tick, - ComponentFixture, - TestComponentBuilder, -} from 'angular2/testing'; -import {Component, DebugElement, EventEmitter} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; - + it, + beforeEach, + inject, + async, + fakeAsync, + flushMicrotasks +} from '@angular/core/testing'; +import {FORM_DIRECTIVES, NgModel, NgControl} from '@angular/common'; +import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; +import {Component, DebugElement} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdCheckbox} from './checkbox'; +import {PromiseCompleter} from '../../core/async/promise-completer'; -// IE11 does not support event constructors, so we need to perform this check. -var BROWSER_SUPPORTS_EVENT_CONSTRUCTORS: boolean = (function() { - // See: https://github.com/rauschma/event_constructors_check/blob/gh-pages/index.html#L39 - try { - return new Event('submit', { bubbles: false }).bubbles === false && - new Event('submit', { bubbles: true }).bubbles === true; - } catch (e) { - return false; - } -})(); -export function main() { - describe('MdCheckbox', function() { - var builder: TestComponentBuilder; - beforeEach(inject([TestComponentBuilder], function(tcb: TestComponentBuilder) { - builder = tcb; - })); +describe('MdCheckbox', () => { + let builder: TestComponentBuilder; + let fixture: ComponentFixture; - it('attaches a class "md-checkbox" to the host element', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el).not.toBeNull(); - }).then(done).catch(done); - }); - it('attaches a unique id to the host element', function(done: () => void) { - builder.createAsync(CheckboxMultiController).then(function(fixture) { - fixture.detectChanges(); - let first = fixture.debugElement.query(By.css('.md-checkbox:first-of-type')); - let second = fixture.debugElement.query(By.css('.md-checkbox:nth-of-type(2)')); - expect(first.nativeElement.id).toMatch(/^md\-checkbox\-\d$/g); - expect(second.nativeElement.id).toMatch(/^md\-checkbox\-\d$/g); - expect(first.nativeElement.id).not.toEqual(second.nativeElement.id); - }).then(done).catch(done); - }); + beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { + builder = tcb; + })); - it('allows clients to provide their own id', function(done: () => void) { - builder.createAsync(CheckboxCustomIdController).then(function(fixture) { - fixture.detectChanges(); - let component = fixture.componentInstance; - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.id).toEqual(component.checkboxId); - }).then(done).catch(done); - }); + describe('basic behaviors', () => { + let checkboxDebugElement: DebugElement; + let checkboxNativeElement: HTMLElement; + let checkboxInstance: MdCheckbox; + let testComponent: SingleCheckbox; - it('creates a label with an id based off the checkbox id', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { + beforeEach(async(() => { + builder.createAsync(SingleCheckbox).then(f => { + fixture = f; fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - let label = el.nativeElement.querySelector('label'); - expect(label.id).toEqual(`${el.nativeElement.id}-label`); - }).then(done).catch(done); - }); - it('uses for the label markup', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - let label = el.nativeElement.querySelector('label'); - expect(label.innerHTML.trim()).toEqual('my checkbox'); - }).then(done).catch(done); - }); + checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox)); + checkboxNativeElement = checkboxDebugElement.nativeElement; + checkboxInstance = checkboxDebugElement.componentInstance; + testComponent = fixture.debugElement.componentInstance; + }); + })); - it('adds a checkbox role attribute to the host element', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('role')).toEqual('checkbox'); - }).then(done).catch(done); - }); + it('should add and remove the checked state', () => { + expect(checkboxInstance.checked).toBe(false); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false'); - it('defaults "aria-checked" to "false" on the host element', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('aria-checked')).toEqual('false'); - }).then(done).catch(done); - }); + testComponent.isChecked = true; + fixture.detectChanges(); - it('defaults "aria-disabled" to "false" on the host element', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('aria-disabled')).toEqual('false'); - }).then(done).catch(done); - }); + expect(checkboxInstance.checked).toBe(true); + expect(checkboxNativeElement.classList).toContain('md-checkbox-checked'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('true'); - it('defaults tabindex to 0 to the host element', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.tabIndex).toEqual(0); - }).then(done).catch(done); - }); + testComponent.isChecked = false; + fixture.detectChanges(); - it('allows clients to provide their own tabindex', function(done: () => void) { - builder.createAsync(CheckboxCustomTabindexController).then(function(fixture) { - fixture.detectChanges(); - let component = fixture.componentInstance; - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.tabIndex).toEqual(component.checkboxTabindex); - }).then(done).catch(done); + expect(checkboxInstance.checked).toBe(false); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false'); }); - it('allows clients to provide an aria-label', function(done: () => void) { - builder.createAsync(CheckboxCustomArialabelController).then(function(fixture) { - fixture.detectChanges(); - let component = fixture.componentInstance; - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('aria-label')).toEqual(component.checkboxLabel); - }).then(done).catch(done); - }); + it('should add and remove indeterminate state', () => { + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-checked'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false'); - it('sets the "aria-labelledby" attribute to the id of the label', function(done: () => void) { - builder.createAsync(CheckboxController).then(function(fixture) { - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - let label = el.nativeElement.querySelector('label'); - expect(el.nativeElement.getAttribute('aria-labelledby')).toEqual(label.id); - }).then(done).catch(done); - }); + testComponent.isIndeterminate = true; + fixture.detectChanges(); - describe('when given an "align" input with a value of "end"', function() { - var fixture: ComponentFixture; + expect(checkboxNativeElement.classList).toContain('md-checkbox-indeterminate'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('mixed'); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxEndAlignedController).then(function(f) { - fixture = f; - fixture.detectChanges(); - }).then(done).catch(done); - }); + testComponent.isIndeterminate = false; + fixture.detectChanges(); - it('sets an "md-checkbox-align-end" class on the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).toContain('md-checkbox-align-end'); - }); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-indeterminate'); + expect(checkboxNativeElement.getAttribute('aria-checked')).toBe('false'); }); - describe(`when the checkbox's checked value is set`, function() { - var fixture: ComponentFixture; - var controller: CheckboxController; - var changePromise: Promise; - var waitingForChange: boolean; - - function waitForChange(): Promise { - if (waitingForChange) { - throw new Error('You are already waiting for a change!'); - } - waitingForChange = true; - return new Promise(function(resolve, reject) { - controller.eventProxy.subscribe(resolve, reject); - }).then(function(val) { - waitingForChange = false; - return val; - }); - } - - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; - - changePromise = waitForChange(); - controller.isChecked = true; - fixture.detectChanges(); - }).then(done).catch(done); - }); + it('should toggle checked state on click', () => { + expect(checkboxInstance.checked).toBe(false); - it('adds a "md-checkbox-checked" modifier class to the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).toContain('md-checkbox-checked'); - }); + checkboxNativeElement.click(); + fixture.detectChanges(); - it('sets "aria-checked" to be "true" on the host element', function() { - let el = fixture.debugElement.query(By.css('md-checkbox')); - controller.isIndeterminate = false; - controller.isChecked = true; - fixture.detectChanges(); - expect(el.nativeElement.getAttribute('aria-checked')).toEqual('true'); - }); - - it('emits a change event with the currently checked value', function(done: () => void) { - changePromise.then(function(isChecked) { - expect(isChecked).toBe(true); + expect(checkboxInstance.checked).toBe(true); - let nextChangePromise = waitForChange(); - controller.isChecked = false; - fixture.detectChanges(); + checkboxNativeElement.click(); + fixture.detectChanges(); - return nextChangePromise; - }).then(function(isChecked) { - expect(isChecked).toBe(false); - }).then(done).catch(done); - }); + expect(checkboxInstance.checked).toBe(false); }); - describe('when the checkbox is indeterminate', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; - - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; + it('should change from indeterminate to checked on click', () => { + testComponent.isIndeterminate = true; + fixture.detectChanges(); - controller.isIndeterminate = true; - fixture.detectChanges(); - }).then(done).catch(done); - }); + checkboxNativeElement.click(); + fixture.detectChanges(); - it('adds a "md-checkbox-indeterminate" class to the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).toContain('md-checkbox-indeterminate'); - }); + expect(checkboxInstance.checked).toBe(true); + expect(checkboxInstance.indeterminate).toBe(false); - it('sets "aria-checked" to "mixed" on the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('aria-checked')).toEqual('mixed'); - }); + checkboxNativeElement.click(); + fixture.detectChanges(); - describe('when re-checked to true', function() { - beforeEach(function() { - controller.isChecked = true; - fixture.detectChanges(); - }); + expect(checkboxInstance.checked).toBe(false); + expect(checkboxInstance.indeterminate).toBe(false); + }); - it('removes md-checkbox-indeterminate', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).not.toContain('md-checkbox-indeterminate'); - }); - }); + it('should add and remove disabled state', () => { + expect(checkboxInstance.disabled).toBe(false); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-disabled'); + expect(checkboxNativeElement.tabIndex).toBe(0); - describe('when re-checked to false', function() { - beforeEach(function() { - controller.isChecked = true; - fixture.detectChanges(); + testComponent.isDisabled = true; + fixture.detectChanges(); - controller.isIndeterminate = true; - fixture.detectChanges(); + expect(checkboxInstance.disabled).toBe(true); + expect(checkboxNativeElement.classList).toContain('md-checkbox-disabled'); + expect(checkboxNativeElement.hasAttribute('tabindex')).toBe(false); - controller.isChecked = false; - fixture.detectChanges(); - }); + testComponent.isDisabled = false; + fixture.detectChanges(); - it('removes md-checkbox-indeterminate', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).not.toContain('md-checkbox-indeterminate'); - }); - }); + expect(checkboxInstance.disabled).toBe(false); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-disabled'); + expect(checkboxNativeElement.tabIndex).toBe(0); }); - describe('when the checkbox is disabled', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; + it('should not toggle `checked` state upon interation while disabled', () => { + testComponent.isDisabled = true; + fixture.detectChanges(); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; - fixture.detectChanges(); + checkboxNativeElement.click(); + expect(checkboxInstance.checked).toBe(false); + }); - controller.isDisabled = true; - fixture.detectChanges(); - }).then(done).catch(done); - }); + it('should overwrite indeterminate state when checked is re-set', () => { + testComponent.isIndeterminate = true; + fixture.detectChanges(); - it('adds a "md-checkbox-disabled" class to the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).toContain('md-checkbox-disabled'); - }); + testComponent.isChecked = true; + fixture.detectChanges(); - it('removes the tabindex attribute from the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.hasAttribute('tabindex')).toBe(false); - }); + expect(checkboxInstance.checked).toBe(true); + expect(checkboxInstance.indeterminate).toBe(false); + }); - it('sets "aria-disabled" to "true" on the host element', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('aria-disabled')).toEqual('true'); - }); + it('should preserve the user-provided id', () => { + expect(checkboxNativeElement.id).toBe('simple-check'); + }); - it('restores the previously set tabindex when re-enabled', function(done: () => void) { - builder.createAsync(CheckboxCustomTabindexController).then(function(f) { - fixture = f; - let tabindexController: CheckboxCustomTabindexController = fixture.componentInstance; - - tabindexController.isDisabled = true; - fixture.detectChanges(); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.hasAttribute('tabindex')).toBe(false); - - tabindexController.isDisabled = false; - fixture.detectChanges(); - el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('tabindex')).toEqual( - String(tabindexController.checkboxTabindex)); - }).then(done).catch(done); - }); + it('should create a label element with its own unique id for aria-labelledby', () => { + let labelElement = checkboxNativeElement.querySelector('label'); + expect(labelElement.id).toBeTruthy(); + expect(labelElement.id).not.toBe(checkboxNativeElement.id); + expect(checkboxNativeElement.getAttribute('aria-labelledby')).toBe(labelElement.id); + }); - describe('when the tabindex input is changed while disabled', function() { - var tabindexController: CheckboxCustomTabindexController; - var newTabindex: number; + it('should project the checkbox content into the label element', () => { + let labelElement = checkboxNativeElement.querySelector('label'); - beforeEach(function(done: () => void) { - newTabindex = 10; + expect(labelElement.textContent.trim()).toBe('Simple checkbox'); + }); - builder.createAsync(CheckboxCustomTabindexController).then(function(f) { - fixture = f; - tabindexController = fixture.componentInstance; + it('should mark the host element with role="checkbox"', () => { + expect(checkboxNativeElement.getAttribute('role')).toBe('checkbox'); + }); - tabindexController.isDisabled = true; - tabindexController.checkboxTabindex = newTabindex; - fixture.detectChanges(); - }).then(done).catch(done); - }); + it('should make the host element a tab stop', () => { + expect(checkboxNativeElement.tabIndex).toBe(0); + }); - it('keeps the tabindex removed from the host', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.hasAttribute('tabindex')).toBe(false); - }); + it('should add a css class to end-align the checkbox', () => { + testComponent.alignment = 'end'; + fixture.detectChanges(); - it('uses the newly changed tabindex when re-enabled', function() { - tabindexController.isDisabled = false; - fixture.detectChanges(); + expect(checkboxNativeElement.classList).toContain('md-checkbox-align-end'); + }); - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.getAttribute('tabindex')).toEqual(String(newTabindex)); - }); + it('should emit a change event when the `checked` value changes', () => { + // TODO(jelbourn): this *should* work with async(), but fixture.whenStable currently doesn't + // know to look at pending macro tasks. + // See https://github.com/angular/angular/issues/8389 + // As a short-term solution, use a promise (which jasmine knows how to understand). + let promiseCompleter = new PromiseCompleter(); + checkboxInstance.change.subscribe(() => { + promiseCompleter.resolve(); }); - }); - describe('when the checkbox is clicked', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; - var el: DebugElement; + testComponent.isChecked = true; + fixture.detectChanges(); - function clickCheckbox(): Event { - return click(el, fixture); - } + return promiseCompleter.promise; + }); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; + it('should stop propagation of interaction events when disabed', () => { + testComponent.isDisabled = true; + fixture.detectChanges(); - fixture.detectChanges(); - el = fixture.debugElement.query(By.css('.md-checkbox')); - }).then(done).catch(done); - }); + checkboxNativeElement.click(); + fixture.detectChanges(); - it('toggles the checked value', function() { - clickCheckbox(); - expect(el.nativeElement.className).toContain('md-checkbox-checked'); + expect(testComponent.parentElementClicked).toBe(false); + }); - clickCheckbox(); - expect(el.nativeElement.className).not.toContain('md-checkbox-checked'); - }); + it('should not scroll when pressing space on the checkbox', () => { + let keyboardEvent = dispatchKeyboardEvent('keydown', checkboxNativeElement, ' '); + fixture.detectChanges(); - describe('when the checkbox is disabled', function() { - beforeEach(function() { - controller.isDisabled = true; - fixture.detectChanges(); - }); - - it('stops the click event from propagating', function() { - let evt = clickCheckbox(); - expect(evt.stopPropagation).toHaveBeenCalled(); - }); - - it('does not alter the checked value', function() { - clickCheckbox(); - expect(el.nativeElement.className).not.toContain('md-checkbox-checked'); - }); - }); + expect(keyboardEvent.preventDefault).toHaveBeenCalled(); }); - describe('when the checkbox is focused', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; - var el: DebugElement; - - function dispatchUIEventOnEl(evtName: string) { - var evt: Event; - if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) { - evt = new Event(evtName); - } else { - evt = document.createEvent('Event'); - evt.initEvent(evtName, true, true); - } - el.nativeElement.dispatchEvent(evt); - fixture.detectChanges(); - } + it('should toggle the checked state when pressing space', () => { + dispatchKeyboardEvent('keyup', checkboxNativeElement, ' '); + fixture.detectChanges(); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; + expect(checkboxInstance.checked).toBe(true); - fixture.detectChanges(); - el = fixture.debugElement.query(By.css('.md-checkbox')); - }).then(done).catch(done); - }); + dispatchKeyboardEvent('keyup', checkboxNativeElement, ' '); + fixture.detectChanges(); - it('blocks spacebar keydown events from performing their default behavior', function() { - dispatchUIEventOnEl('focus'); + expect(checkboxInstance.checked).toBe(false); + }); - var evt = keydown(el, ' ', fixture); - expect(evt.preventDefault).toHaveBeenCalled(); - }); + it('should not toggle the checked state when pressing space if disabled', () => { + testComponent.isDisabled = true; + fixture.detectChanges(); - it('does not block other keyboard events from performing their default behavior', function() { - dispatchUIEventOnEl('focus'); + dispatchKeyboardEvent('keyup', checkboxNativeElement, ' '); + fixture.detectChanges(); - var evt = keydown(el, 'Tab', fixture); - expect(evt.preventDefault).not.toHaveBeenCalled(); - }); + expect(checkboxInstance.checked).toBe(false); + expect(testComponent.parentElementKeyedUp).toBe(false); }); - describe('when a spacebar press occurs on the checkbox', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; - var el: DebugElement; + describe('state transition css classes', () => { + it('should transition unchecked -> checked -> unchecked', () => { + testComponent.isChecked = true; + fixture.detectChanges(); + expect(checkboxNativeElement.classList).toContain('md-checkbox-anim-unchecked-checked'); - function spacePress(): Event { - return keyup(el, ' ', fixture); - } + testComponent.isChecked = false; + fixture.detectChanges(); + expect(checkboxNativeElement.classList).not.toContain('md-checkbox-anim-unchecked-checked'); + expect(checkboxNativeElement.classList).toContain('md-checkbox-anim-checked-unchecked'); + }); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; + it('should transition unchecked -> indeterminate -> unchecked', () => { + testComponent.isIndeterminate = true; + fixture.detectChanges(); - fixture.detectChanges(); - el = fixture.debugElement.query(By.css('.md-checkbox')); - }).then(done).catch(done); - }); + expect(checkboxNativeElement.classList) + .toContain('md-checkbox-anim-unchecked-indeterminate'); - it('toggles the checked value', function() { - spacePress(); - expect(el.nativeElement.className).toContain('md-checkbox-checked'); + testComponent.isIndeterminate = false; + fixture.detectChanges(); - spacePress(); - expect(el.nativeElement.className).not.toContain('md-checkbox-checked'); + expect(checkboxNativeElement.classList) + .not.toContain('md-checkbox-anim-unchecked-indeterminate'); + expect(checkboxNativeElement.classList) + .toContain('md-checkbox-anim-indeterminate-unchecked'); }); - describe('when the checkbox is disabled', function() { - beforeEach(function() { - controller.isDisabled = true; - fixture.detectChanges(); - }); - - it('stops the click event from propagating', function() { - let evt = spacePress(); - expect(evt.stopPropagation).toHaveBeenCalled(); - }); - - it('does not alter the checked value', function() { - spacePress(); - expect(el.nativeElement.className).not.toContain('md-checkbox-checked'); - }); - }); - }); + it('should transition indeterminate -> checked', () => { + testComponent.isIndeterminate = true; + fixture.detectChanges(); - describe('usage as a form control', function() { - var fixture: ComponentFixture; - var controller: CheckboxFormcontrolController; + testComponent.isChecked = true; + fixture.detectChanges(); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxFormcontrolController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; - fixture.detectChanges(); - }).then(done).catch(done); + expect(checkboxNativeElement.classList).not.toContain( + 'md-checkbox-anim-unchecked-indeterminate'); + expect(checkboxNativeElement.classList).toContain('md-checkbox-anim-indeterminate-checked'); }); - // NOTE(traviskaufman): This test is not that elegant, but I have not found a better way - // to test through ngModel as of now. - // See: https://github.com/angular/angular/issues/7409 - it('supports ngModel/ngControl', function(done: () => void) { - var el: DebugElement; - var invalidMsg: DebugElement; - - fakeAsync(function() { - el = fixture.debugElement.query(By.css('.md-checkbox')); - invalidMsg = fixture.debugElement.query(By.css('#invalid-msg')); - - fixture.detectChanges(); - tick(); - expect(el.nativeElement.className).toContain('ng-untouched'); - expect(el.nativeElement.className).toContain('ng-pristine'); - expect(invalidMsg.nativeElement.hidden).toBe(true); - - controller.model.isChecked = true; - fixture.detectChanges(); - tick(); - fixture.detectChanges(); - - expect(el.nativeElement.className).toContain('md-checkbox-checked'); - expect(el.nativeElement.className).toContain('ng-dirty'); - expect(el.nativeElement.className).toContain('ng-valid'); - - var blur: Event; - if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) { - blur = new Event('blur'); - } else { - blur = document.createEvent('UIEvent'); - (blur).initUIEvent('blur', true, true, window, 0); - } - el.nativeElement.dispatchEvent(blur); - fixture.detectChanges(); - tick(); - expect(el.nativeElement.className).toContain('ng-touched'); - })(); - - let onceChanged = controller.model.waitForChange(); - click(el, fixture); - onceChanged.then(function() { - expect(controller.model.isChecked).toBe(false); - }).then(done).catch(done); - }); - }); + it('should not apply transition classes when there is no state change', () => { + testComponent.isChecked = checkboxInstance.checked; + fixture.detectChanges(); + expect(checkboxNativeElement).not.toMatch(/^md\-checkbox\-anim/g); - describe('applying transition classes', function() { - var fixture: ComponentFixture; - var controller: CheckboxController; + testComponent.isIndeterminate = checkboxInstance.indeterminate; + expect(checkboxNativeElement).not.toMatch(/^md\-checkbox\-anim/g); + }); - beforeEach(function(done: () => void) { - builder.createAsync(CheckboxController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; - fixture.detectChanges(); - }).then(done).catch(done); + it('should not initially have any transition classes', () => { + expect(checkboxNativeElement).not.toMatch(/^md\-checkbox\-anim/g); }); + }); + }); - it('applies transition classes when going from unchecked <-> checked', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); + describe('with provided aria-label ', () => { + let checkboxDebugElement: DebugElement; + let checkboxNativeElement: HTMLElement; - controller.isChecked = true; - fixture.detectChanges(); - expect(el.nativeElement.className).toContain('md-checkbox-anim-unchecked-checked'); + it('should use the provided aria-label', async(() => { + builder.createAsync(CheckboxWithAriaLabel).then(f => { + fixture = f; + checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox)); + checkboxNativeElement = checkboxDebugElement.nativeElement; - controller.isChecked = false; - fixture.detectChanges(); - expect(el.nativeElement.className).not.toContain('md-checkbox-anim-unchecked-checked'); - expect(el.nativeElement.className).toContain('md-checkbox-anim-checked-unchecked'); + expect(checkboxNativeElement.getAttribute('aria-label')).toBe('Super effective'); }); + })); + }); - it('applies transition classes when going from unchecked <-> indeterminate', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); + describe('with provided tabIndex', () => { + let checkboxDebugElement: DebugElement; + let checkboxNativeElement: HTMLElement; + let testComponent: CheckboxWithTabIndex; - controller.isIndeterminate = true; + beforeEach(async(() => { + builder.createAsync(CheckboxWithTabIndex).then(f => { + fixture = f; fixture.detectChanges(); - expect(el.nativeElement.className).toContain('md-checkbox-anim-unchecked-indeterminate'); - controller.isIndeterminate = false; - fixture.detectChanges(); - expect(el.nativeElement.className).not.toContain( - 'md-checkbox-anim-unchecked-indeterminate'); - expect(el.nativeElement.className).toContain('md-checkbox-anim-indeterminate-unchecked'); + testComponent = fixture.debugElement.componentInstance; + checkboxDebugElement = fixture.debugElement.query(By.directive(MdCheckbox)); + checkboxNativeElement = checkboxDebugElement.nativeElement; }); + })); - it('applies a transition class when going from checked -> indeterminate', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); + it('should preserve any given tabIndex', async(() => { + expect(checkboxNativeElement.tabIndex).toBe(7); + })); - controller.isChecked = true; - fixture.detectChanges(); + it('should preserve given tabIndex when the checkbox is disabled then enabled', () => { + testComponent.isDisabled = true; + fixture.detectChanges(); - controller.isIndeterminate = true; - fixture.detectChanges(); - expect(el.nativeElement.className).not.toContain('md-checkbox-anim-unchecked-checked'); - expect(el.nativeElement.className).toContain('md-checkbox-anim-checked-indeterminate'); - }); + testComponent.customTabIndex = 13; + fixture.detectChanges(); - it('applies a transition class when going from indeterminate -> checked', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); + testComponent.isDisabled = false; + fixture.detectChanges(); - controller.isIndeterminate = true; - fixture.detectChanges(); + expect(checkboxNativeElement.tabIndex).toBe(13); + }); + }); - controller.isChecked = true; + describe('with multiple checkboxes', () => { + beforeEach(async(() => { + builder.createAsync(MultipleCheckboxes).then(f => { + fixture = f; fixture.detectChanges(); - expect(el.nativeElement.className).not.toContain( - 'md-checkbox-anim-unchecked-indeterminate'); - expect(el.nativeElement.className).toContain('md-checkbox-anim-indeterminate-checked'); }); + })); - it('does not apply any transition classes when there is nothing to transition', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); + it('should assign a unique id to each checkbox', () => { + let [firstId, secondId] = + fixture.debugElement.queryAll(By.directive(MdCheckbox)) + .map(debugElement => debugElement.nativeElement.id); - controller.isChecked = controller.isChecked; - fixture.detectChanges(); - expect(el.nativeElement.className).not.toMatch(/^md\-checkbox\-anim/g); + expect(firstId).toBeTruthy(); + expect(secondId).toBeTruthy(); + expect(firstId).not.toEqual(secondId); + }); + }); - controller.isIndeterminate = controller.isIndeterminate; - fixture.detectChanges(); - expect(el.nativeElement.className).not.toMatch(/^md\-checkbox\-anim/g); + describe('with ngModel and ngControl', () => { + beforeEach(async(() => { + builder.createAsync(CheckboxWithFormDirectives).then(f => { + f.detectChanges(); + fixture = f; }); + })); - it('does not apply any transition classes when the component is initialized', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - expect(el.nativeElement.className).not.toMatch(/^md\-checkbox\-anim/g); - }); + it('should be in pristine, untouched, and valid states initially', fakeAsync(() => { + flushMicrotasks(); - describe('when interacted with from the initial state', function() { - beforeEach(function(done: any) { - builder.createAsync(CheckboxBarebonesController).then(function(f) { - fixture = f; - controller = fixture.componentInstance; - fixture.detectChanges(); - }).then(done).catch(done.fail); - }); - - it('applies a transition class when checked', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - click(el, fixture); - expect(el.nativeElement.className).toContain('md-checkbox-anim-unchecked-checked'); - }); - - it('applies a transition class when made indeterminate', function() { - let el = fixture.debugElement.query(By.css('.md-checkbox')); - controller.isIndeterminate = true; - fixture.detectChanges(); - expect(el.nativeElement.className).toContain('md-checkbox-anim-unchecked-indeterminate'); - }); - }); - }); - }); -} + let checkboxElement = fixture.debugElement.query(By.directive(MdCheckbox)); + let ngControl = checkboxElement.injector.get(NgControl); -function click(el: DebugElement, fixture: ComponentFixture) { - var clickEvent: Event; - if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) { - clickEvent = new Event('click'); - } else { - clickEvent = document.createEvent('UIEvent'); - (clickEvent).initUIEvent('click', true, true, window, 1); - } - spyOn(clickEvent, 'stopPropagation').and.callThrough(); - el.nativeElement.dispatchEvent(clickEvent); - fixture.detectChanges(); - return clickEvent; -} + expect(ngControl.valid).toBe(true); + expect(ngControl.pristine).toBe(true); + expect(ngControl.touched).toBe(false); -// TODO(traviskaufman): Reinvestigate implementation of this method once tests in Dart begin to run. -function keyEvent(name: string, el: DebugElement, key: string, fixture: ComponentFixture): Event { - var kbdEvent: Event; - if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) { - kbdEvent = new KeyboardEvent(name); - } else { - kbdEvent = document.createEvent('Event'); - kbdEvent.initEvent(name, true, true); - } - // Hack DOM Level 3 Events "key" prop into keyboard event. - Object.defineProperty(kbdEvent, 'key', { - value: key, - enumerable: false, - writable: false, - configurable: true + // TODO(jelbourn): test that `touched` and `pristine` state are modified appropriately. + // This is currently blocked on issues with async() and fakeAsync(). + })); }); - spyOn(kbdEvent, 'preventDefault').and.callThrough(); - spyOn(kbdEvent, 'stopPropagation').and.callThrough(); - el.nativeElement.dispatchEvent(kbdEvent); - fixture.detectChanges(); - return kbdEvent; -} -function keydown(el: DebugElement, key: string, fixture: ComponentFixture): Event { - return keyEvent('keydown', el, key, fixture); -} +}); -function keyup(el: DebugElement, key: string, fixture: ComponentFixture): Event { - return keyEvent('keyup', el, key, fixture); -} +/** Simple component for testing a single checkbox. */ @Component({ - selector: 'checkbox-controller', + directives: [MdCheckbox], template: ` - - my checkbox +
+ + Simple checkbox - `, - directives: [MdCheckbox] +
` }) -class CheckboxController { +class SingleCheckbox { + alignment: string = 'start'; isChecked: boolean = false; isIndeterminate: boolean = false; isDisabled: boolean = false; - eventProxy: EventEmitter = new EventEmitter(); + parentElementClicked: boolean = false; + parentElementKeyedUp: boolean = false; + lastKeydownEvent: Event = null; } +/** Simple component for testing an MdCheckbox with ngModel and ngControl. */ @Component({ - selector: 'checkbox-multi-controller', + directives: [MdCheckbox, FORM_DIRECTIVES, NgModel], template: ` - - +
+ Be good +
`, - directives: [MdCheckbox] }) -class CheckboxMultiController {} +class CheckboxWithFormDirectives { + isGood: boolean = false; +} -@Component({ - selector: 'checkbox-custom-id-controller', +/** Simple test component with multiple checkboxes. */ +@Component(({ + directives: [MdCheckbox], template: ` - - `, - directives: [MdCheckbox] -}) -class CheckboxCustomIdController { - checkboxId: string = 'my-checkbox'; -} + Option 1 + Option 2 + ` +})) +class MultipleCheckboxes { } + +/** Simple test component with tabIndex */ @Component({ - selector: 'checkbox-custom-tabindex-controller', + directives: [MdCheckbox], template: ` - - `, - directives: [MdCheckbox] + + `, }) -class CheckboxCustomTabindexController { - checkboxTabindex: number = 5; +class CheckboxWithTabIndex { + customTabIndex: number = 7; isDisabled: boolean = false; } +/** Simple test component with an aria-label set. */ @Component({ - selector: 'checkbox-custom-arialabel-controller', - template: ` - - `, - directives: [MdCheckbox] + directives: [MdCheckbox], + template: `` }) -class CheckboxCustomArialabelController { - checkboxLabel: string = 'My awesome checkbox'; -} +class CheckboxWithAriaLabel { } -class FormcontrolModel { - private _isChecked = false; - private _changeEmitter = new EventEmitter(); +// TODO(jelbourn): remove eveything below when Angular supports faking events. - get isChecked(): boolean { - return this._isChecked; - } - set isChecked(isChecked: boolean) { - let shouldEmitChange = this._isChecked !== isChecked; - this._isChecked = isChecked; - if (shouldEmitChange) { - this._changeEmitter.emit(this._isChecked); - } +var BROWSER_SUPPORTS_EVENT_CONSTRUCTORS: boolean = (function() { + // See: https://github.com/rauschma/event_constructors_check/blob/gh-pages/index.html#L39 + try { + return new Event('submit', { bubbles: false }).bubbles === false && + new Event('submit', { bubbles: true }).bubbles === true; + } catch (e) { + return false; } +})(); - waitForChange(): Promise { - return new Promise((resolve, reject) => { - let subscription: {unsubscribe: () => void}; - let subscriber = function(isChecked: boolean) { - subscription.unsubscribe(); - resolve(isChecked); - }; - subscription = this._changeEmitter.subscribe(subscriber, reject); - }); + +/** + * Dispatches a keyboard event from an element. + * @param eventName The name of the event to dispatch, such as "keydown". + * @param element The element from which the event will be dispatched. + * @param key The key tied to the KeyboardEvent. + * @returns The artifically created keyboard event. + */ +function dispatchKeyboardEvent(eventName: string, element: HTMLElement, key: string): Event { + let keyboardEvent: Event; + if (BROWSER_SUPPORTS_EVENT_CONSTRUCTORS) { + keyboardEvent = new KeyboardEvent(eventName); + } else { + keyboardEvent = document.createEvent('Event'); + keyboardEvent.initEvent(eventName, true, true); } -} -@Component({ - selector: 'checkbox-formcontrol-controller', - template: ` -
- - -

INVALID!

-
- `, - directives: [MdCheckbox] -}) -class CheckboxFormcontrolController { - model = new FormcontrolModel(); -} + // Hack DOM Level 3 Events "key" prop into keyboard event. + Object.defineProperty(keyboardEvent, 'key', { + value: key, + enumerable: false, + writable: false, + configurable: true, + }); -@Component({ - selector: 'checkbox-end-aligned-controller', - template: ``, - directives: [MdCheckbox] -}) -class CheckboxEndAlignedController {} + // Using spyOn seems to be the *only* way to determine if preventDefault is called, since it + // seems that `defaultPrevented` does not get set with the technique. + spyOn(keyboardEvent, 'preventDefault').and.callThrough(); -@Component({ - selector: 'checkbox-barebones-controller', - template: ``, - directives: [MdCheckbox] -}) -class CheckboxBarebonesController { - public isIndeterminate: boolean = false; + element.dispatchEvent(keyboardEvent); + return keyboardEvent; } + diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts index d91883185d60..8ac0105ea657 100644 --- a/src/components/checkbox/checkbox.ts +++ b/src/components/checkbox/checkbox.ts @@ -8,13 +8,14 @@ import { Provider, Renderer, ViewEncapsulation, - forwardRef -} from 'angular2/core'; - + forwardRef, +} from '@angular/core'; import { NG_VALUE_ACCESSOR, - ControlValueAccessor -} from 'angular2/src/common/forms/directives/control_value_accessor'; + ControlValueAccessor, +} from '@angular/common'; + + /** * Monotonically increasing integer used to auto-generate unique ids for checkbox components. @@ -60,7 +61,6 @@ enum TransitionCheckState { host: { 'role': 'checkbox', '[id]': 'id', - '[class.md-checkbox]': 'true', '[class.md-checkbox-indeterminate]': 'indeterminate', '[class.md-checkbox-checked]': 'checked', '[class.md-checkbox-disabled]': 'disabled', @@ -110,6 +110,9 @@ export class MdCheckbox implements ControlValueAccessor { /** Called when the checkbox is blurred. Needed to properly implement ControlValueAccessor. */ onTouched: () => any = () => {}; + /** Whether the `checked` state has been set to its initial value. */ + private _isInitialized: boolean = false; + private _currentAnimationClass: string = ''; private _currentCheckState: TransitionCheckState = TransitionCheckState.Init; @@ -131,11 +134,19 @@ export class MdCheckbox implements ControlValueAccessor { } set checked(checked: boolean) { - this._indeterminate = false; - this._checked = checked; - this._transitionCheckState( - this._checked ? TransitionCheckState.Checked : TransitionCheckState.Unchecked); - this.change.emit(this._checked); + if (checked != this.checked) { + this._indeterminate = false; + this._checked = checked; + this._transitionCheckState( + this._checked ? TransitionCheckState.Checked : TransitionCheckState.Unchecked); + + // Only fire a change event if this isn't the first time the checked property is ever set. + if (this._isInitialized) { + this.change.emit(this._checked); + } + } + + this._isInitialized = true; } /** diff --git a/src/components/grid-list/grid-list.ts b/src/components/grid-list/grid-list.ts index beea794f5e7c..8853bbdca372 100644 --- a/src/components/grid-list/grid-list.ts +++ b/src/components/grid-list/grid-list.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; @Component({ selector: 'md-grid-list', diff --git a/src/components/icon/fake-svgs.ts b/src/components/icon/fake-svgs.ts index 791996498b63..7a9a08a12ce2 100644 --- a/src/components/icon/fake-svgs.ts +++ b/src/components/icon/fake-svgs.ts @@ -1,6 +1,6 @@ import { Response, - ResponseOptions} from 'angular2/http'; + ResponseOptions} from '@angular/http'; /** * Fake URLs and associated SVG documents used by tests. diff --git a/src/components/icon/icon-registry.ts b/src/components/icon/icon-registry.ts index 27704ff18d90..9fd8be75ae7f 100644 --- a/src/components/icon/icon-registry.ts +++ b/src/components/icon/icon-registry.ts @@ -1,11 +1,10 @@ -import {Injectable} from 'angular2/core'; -import {BaseException} from 'angular2/src/facade/exceptions'; -import {Http} from 'angular2/http'; +import {Injectable} from '@angular/core'; +import {Http} from '@angular/http'; import {Observable} from 'rxjs/Rx'; /** Exception thrown when attempting to load an icon with a name that cannot be found. */ -export class MdIconNameNotFoundException extends BaseException { +export class MdIconNameNotFoundError extends Error { constructor(iconName: string) { super(`Unable to find icon with the name "${iconName}"`); } @@ -15,7 +14,7 @@ export class MdIconNameNotFoundException extends BaseException { * Exception thrown when attempting to load SVG content that does not contain the expected * tag. */ -export class MdIconSvgTagNotFoundException extends BaseException { +export class MdIconSvgTagNotFoundError extends Error { constructor() { super(' tag not found'); } @@ -153,7 +152,7 @@ export class MdIconRegistry { /** * Returns an Observable that produces the icon (as an DOM element) with the given name * and namespace. The icon must have been previously registered with addIcon or addIconSet; - * if not, the Observable will throw an MdIconNameNotFoundException. + * if not, the Observable will throw an MdIconNameNotFoundError. */ getNamedSvgIcon(name: string, namespace = ''): Observable { // Return (copy of) cached icon if possible. @@ -166,7 +165,7 @@ export class MdIconRegistry { if (iconSetConfigs) { return this._getSvgFromIconSetConfigs(name, iconSetConfigs); } - return Observable.throw(new MdIconNameNotFoundException(key)); + return Observable.throw(new MdIconNameNotFoundError(key)); } /** @@ -190,7 +189,7 @@ export class MdIconRegistry { * if found copies the element to a new element. If not found, fetches all icon sets * that have not been cached, and searches again after all fetches are completed. * The returned Observable produces the SVG element if possible, and throws - * MdIconNameNotFoundException if no icon with the specified name can be found. + * MdIconNameNotFoundError if no icon with the specified name can be found. */ private _getSvgFromIconSetConfigs(name: string, iconSetConfigs: SvgIconConfig[]): Observable { @@ -227,7 +226,7 @@ export class MdIconRegistry { .map((ignoredResults: any) => { const foundIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs); if (!foundIcon) { - throw new MdIconNameNotFoundException(name); + throw new MdIconNameNotFoundError(name); } return foundIcon; }); @@ -318,7 +317,7 @@ export class MdIconRegistry { div.innerHTML = str; const svg = div.querySelector('svg'); if (!svg) { - throw new MdIconSvgTagNotFoundException(); + throw new MdIconSvgTagNotFoundError(); } return svg; } diff --git a/src/components/icon/icon.spec.ts b/src/components/icon/icon.spec.ts index b9bd6cb8bacc..6390ff083137 100644 --- a/src/components/icon/icon.spec.ts +++ b/src/components/icon/icon.spec.ts @@ -5,11 +5,11 @@ import { beforeEach, beforeEachProviders, inject, - TestComponentBuilder -} from 'angular2/testing'; -import {HTTP_PROVIDERS, XHRBackend} from 'angular2/http'; -import {MockBackend} from 'angular2/http/testing'; -import {provide, Component} from 'angular2/core'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {HTTP_PROVIDERS, XHRBackend} from '@angular/http'; +import {MockBackend} from '@angular/http/testing'; +import {provide, Component} from '@angular/core'; import {MdIcon} from './icon'; import {MdIconRegistry} from './icon-registry'; import {getFakeSvgHttpResponse} from './fake-svgs'; diff --git a/src/components/icon/icon.ts b/src/components/icon/icon.ts index 04b5d1154447..7d312ceea969 100644 --- a/src/components/icon/icon.ts +++ b/src/components/icon/icon.ts @@ -9,14 +9,13 @@ import { SimpleChange, ViewEncapsulation, AfterViewChecked -} from 'angular2/core'; -import {BaseException} from 'angular2/src/facade/exceptions'; +} from '@angular/core'; import {MdIconRegistry} from './icon-registry'; /** Exception thrown when an invalid icon name is passed to an md-icon component. */ -export class MdIconInvalidNameException extends BaseException { +export class MdIconInvalidNameError extends Error { constructor(iconName: string) { super(`Invalid icon name: "${name}"`); } @@ -89,12 +88,12 @@ export class MdIcon implements OnChanges, OnInit, AfterViewChecked { * The separator for the two fields is ':'. If there is no separator, an empty * string is returned for the icon set and the entire value is returned for * the icon name. If the argument is falsy, returns an array of two empty strings. - * Throws a MdIconInvalidNameException if the name contains two or more ':' separators. + * Throws a MdIconInvalidNameError if the name contains two or more ':' separators. * Examples: * 'social:cake' -> ['social', 'cake'] * 'penguin' -> ['', 'penguin'] * null -> ['', ''] - * 'a:b:c' -> (throws MdIconInvalidNameException) + * 'a:b:c' -> (throws MdIconInvalidNameError) */ private _splitIconName(iconName: string): [string, string] { if (!iconName) { @@ -108,7 +107,7 @@ export class MdIcon implements OnChanges, OnInit, AfterViewChecked { case 2: return <[string, string]>parts; default: - throw new MdIconInvalidNameException(iconName); + throw new MdIconInvalidNameError(iconName); } } diff --git a/src/components/input/input.spec.ts b/src/components/input/input.spec.ts index 24ad7d0a8f83..9d4f393b4b8e 100644 --- a/src/components/input/input.spec.ts +++ b/src/components/input/input.spec.ts @@ -5,11 +5,11 @@ import { beforeEach, fakeAsync, inject, - TestComponentBuilder, tick, -} from 'angular2/testing'; -import {Component} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; import { MdInput, MD_INPUT_DIRECTIVES, @@ -88,7 +88,7 @@ export function main() { .then(fixture => { expect(() => fixture.detectChanges()) .toThrow(); - // TODO(jelbourn): .toThrow(new MdInputDuplicatedHintException('start')); + // TODO(jelbourn): .toThrow(new MdInputDuplicatedHintError('start')); // See https://github.com/angular/angular/issues/8348 }); }); @@ -98,7 +98,7 @@ export function main() { .then(fixture => { expect(() => fixture.detectChanges()) .toThrow(); - // TODO(jelbourn): .toThrow(new MdInputDuplicatedHintException('start')); + // TODO(jelbourn): .toThrow(new MdInputDuplicatedHintError('start')); // See https://github.com/angular/angular/issues/8348 }); }); @@ -108,7 +108,7 @@ export function main() { .then(fixture => { expect(() => fixture.detectChanges()) .toThrow(); - // TODO(jelbourn): .toThrow(new MdInputPlaceholderConflictException()); + // TODO(jelbourn): .toThrow(new MdInputPlaceholderConflictError()); // See https://github.com/angular/angular/issues/8348 }); }); @@ -122,7 +122,7 @@ export function main() { // hard to build a full exception to compare with. // We just check for any exception in this case. expect(() => fixture.detectChanges()) - .toThrow(/* new MdInputUnsupportedTypeException('file') */); + .toThrow(/* new MdInputUnsupportedTypeError('file') */); })(); }); }); diff --git a/src/components/input/input.ts b/src/components/input/input.ts index d3a1a00eff94..c90d27ae0a4c 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -11,12 +11,11 @@ import { ContentChildren, QueryList, OnChanges, -} from 'angular2/core'; +} from '@angular/core'; import { NG_VALUE_ACCESSOR, ControlValueAccessor -} from 'angular2/src/common/forms/directives/control_value_accessor'; -import {BaseException} from 'angular2/src/facade/exceptions'; +} from '@angular/common'; import {BooleanFieldValue} from '../../core/annotations/field-value'; @@ -28,7 +27,7 @@ const MD_INPUT_CONTROL_VALUE_ACCESSOR = new Provider( multi: true }); -// Invalid input type. Using one of these will throw an MdInputUnsupportedTypeException. +// Invalid input type. Using one of these will throw an MdInputUnsupportedTypeError. const MD_INPUT_INVALID_INPUT_TYPE = [ 'file', 'radio', @@ -39,19 +38,19 @@ const MD_INPUT_INVALID_INPUT_TYPE = [ let nextUniqueId = 0; -export class MdInputPlaceholderConflictException extends BaseException { +export class MdInputPlaceholderConflictError extends Error { constructor() { super('Placeholder attribute and child element were both specified.'); } } -export class MdInputUnsupportedTypeException extends BaseException { +export class MdInputUnsupportedTypeError extends Error { constructor(type: string) { super(`Input type "${type}" isn't supported by md-input.`); } } -export class MdInputDuplicatedHintException extends BaseException { +export class MdInputDuplicatedHintError extends Error { constructor(align: string) { super(`A hint was already declared for 'align="${align}"'.`); } @@ -227,10 +226,10 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange */ private _validateConstraints() { if (this.placeholder != '' && this.placeholder != null && this._placeholderChild != null) { - throw new MdInputPlaceholderConflictException(); + throw new MdInputPlaceholderConflictError(); } if (MD_INPUT_INVALID_INPUT_TYPE.indexOf(this.type) != -1) { - throw new MdInputUnsupportedTypeException(this.type); + throw new MdInputUnsupportedTypeError(this.type); } if (this._hintChildren) { @@ -240,12 +239,12 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange this._hintChildren.forEach((hint: MdHint) => { if (hint.align == 'start') { if (startHint || this.hintLabel) { - throw new MdInputDuplicatedHintException('start'); + throw new MdInputDuplicatedHintError('start'); } startHint = hint; } else if (hint.align == 'end') { if (endHint) { - throw new MdInputDuplicatedHintException('end'); + throw new MdInputDuplicatedHintError('end'); } endHint = hint; } diff --git a/src/components/list/list.spec.ts b/src/components/list/list.spec.ts index 2c5688e7857d..1f19aa1f7f7b 100644 --- a/src/components/list/list.spec.ts +++ b/src/components/list/list.spec.ts @@ -4,10 +4,10 @@ import { expect, beforeEach, inject, - TestComponentBuilder -} from 'angular2/testing'; -import {Component} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MD_LIST_DIRECTIVES} from './list'; diff --git a/src/components/list/list.ts b/src/components/list/list.ts index ccba49c9f4ff..d70990fcbe6f 100644 --- a/src/components/list/list.ts +++ b/src/components/list/list.ts @@ -1,5 +1,16 @@ -import {Component, ViewEncapsulation, ContentChildren, ContentChild, QueryList, Directive, - ElementRef, Renderer, AfterContentInit} from 'angular2/core'; +import { + Component, + ViewEncapsulation, + ContentChildren, + ContentChild, + QueryList, + Directive, + ElementRef, + Renderer, + AfterContentInit, +} from '@angular/core'; + + @Component({ selector: 'md-list, md-nav-list', diff --git a/src/components/progress-bar/progress-bar.spec.ts b/src/components/progress-bar/progress-bar.spec.ts index 8e7932d16386..505f2b17483b 100644 --- a/src/components/progress-bar/progress-bar.spec.ts +++ b/src/components/progress-bar/progress-bar.spec.ts @@ -1,6 +1,7 @@ -import {beforeEach, describe, expect, inject, it, TestComponentBuilder} from 'angular2/testing'; -import {Component} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +import {beforeEach, describe, expect, inject, it} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdProgressBar} from './progress-bar'; diff --git a/src/components/progress-bar/progress-bar.ts b/src/components/progress-bar/progress-bar.ts index d07581d5ff05..0f5efc0c93df 100644 --- a/src/components/progress-bar/progress-bar.ts +++ b/src/components/progress-bar/progress-bar.ts @@ -3,8 +3,7 @@ import { ChangeDetectionStrategy, HostBinding, Input, -} from 'angular2/core'; -import {isPresent} from 'angular2/src/facade/lang'; +} from '@angular/core'; // TODO(josephperrott): Benchpress tests. @@ -38,9 +37,7 @@ export class MdProgressBar { return this._value; } set value(v: number) { - if (isPresent(v)) { - this._value = MdProgressBar.clamp(v); - } + this._value = MdProgressBar.clamp(v || 0); } @@ -55,9 +52,7 @@ export class MdProgressBar { return this._bufferValue; } set bufferValue(v: number) { - if (isPresent(v)) { - this._bufferValue = MdProgressBar.clamp(v); - } + this._bufferValue = MdProgressBar.clamp(v || 0); } diff --git a/src/components/progress-circle/progress-circle.spec.ts b/src/components/progress-circle/progress-circle.spec.ts index dbf3a6d78bb1..2cb19b6c1d36 100644 --- a/src/components/progress-circle/progress-circle.spec.ts +++ b/src/components/progress-circle/progress-circle.spec.ts @@ -4,9 +4,10 @@ import { expect, beforeEach, inject, - TestComponentBuilder} from 'angular2/testing'; -import {Component, DebugElement} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component, DebugElement} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdProgressCircle} from './progress-circle'; diff --git a/src/components/progress-circle/progress-circle.ts b/src/components/progress-circle/progress-circle.ts index 5b0bc877d0f9..34655b893733 100644 --- a/src/components/progress-circle/progress-circle.ts +++ b/src/components/progress-circle/progress-circle.ts @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, HostBinding, Input -} from 'angular2/core'; +} from '@angular/core'; // TODO(josephperrott): Benchpress tests. diff --git a/src/components/radio/radio.spec.ts b/src/components/radio/radio.spec.ts index d00a106ca707..ca408650f200 100644 --- a/src/components/radio/radio.spec.ts +++ b/src/components/radio/radio.spec.ts @@ -6,10 +6,10 @@ import { fakeAsync, inject, tick, - TestComponentBuilder -} from 'angular2/testing'; -import {Component, DebugElement} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {Component, DebugElement} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdRadioButton, MdRadioGroup, MdRadioChange} from './radio'; import {MdRadioDispatcher} from './radio_dispatcher'; diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index 1301ed83999f..8310a1919d6a 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -14,16 +14,18 @@ import { QueryList, ViewEncapsulation, forwardRef -} from 'angular2/core'; - +} from '@angular/core'; import { NG_VALUE_ACCESSOR, ControlValueAccessor -} from 'angular2/src/common/forms/directives/control_value_accessor'; - +} from '@angular/common'; import {MdRadioDispatcher} from './radio_dispatcher'; + + export {MdRadioDispatcher} from './radio_dispatcher'; + + /** * Provider Expression that allows md-radio-group to register as a ControlValueAccessor. This * allows it to support [(ngModel)] and ngControl. diff --git a/src/components/radio/radio_dispatcher.ts b/src/components/radio/radio_dispatcher.ts index f142b9c6b797..cfd6d9eee1f9 100644 --- a/src/components/radio/radio_dispatcher.ts +++ b/src/components/radio/radio_dispatcher.ts @@ -1,4 +1,6 @@ -import {Injectable} from 'angular2/core'; +import {Injectable} from '@angular/core'; + + /** * Class for radio buttons to coordinate unique selection based on name. diff --git a/src/components/sidenav/sidenav.spec.ts b/src/components/sidenav/sidenav.spec.ts index 779f759e7f24..f63429e3443f 100644 --- a/src/components/sidenav/sidenav.spec.ts +++ b/src/components/sidenav/sidenav.spec.ts @@ -3,21 +3,20 @@ import { describe, expect, beforeEach, - ComponentFixture, - TestComponentBuilder, fakeAsync, inject, injectAsync, tick -} from 'angular2/testing'; -import {XHR} from 'angular2/src/compiler/xhr'; +} from '@angular/core/testing'; +import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; +import {XHR} from '@angular/compiler'; import { Component, Type, ViewMetadata -} from 'angular2/core'; +} from '@angular/core'; -import {By} from 'angular2/platform/browser'; +import {By} from '@angular/platform-browser'; import {MdSidenav, MdSidenavLayout, MD_SIDENAV_DIRECTIVES} from './sidenav'; @@ -30,8 +29,8 @@ function fakeAsyncAdaptor(fn: () => void) { * Create a ComponentFixture from the builder. This takes a template and a style for sidenav. */ function createFixture(appType: Type, builder: TestComponentBuilder, - template: string, style: string): ComponentFixture { - let fixture: ComponentFixture = null; + template: string, style: string): ComponentFixture { + let fixture: ComponentFixture = null; // Remove the styles (which remove the animations/transitions). builder .overrideView(MdSidenavLayout, new ViewMetadata({ @@ -39,14 +38,14 @@ function createFixture(appType: Type, builder: TestComponentBuilder, styles: [style], directives: [MdSidenav], })) - .createAsync(appType).then((f: ComponentFixture) => { fixture = f; }); + .createAsync(appType).then((f: ComponentFixture) => { fixture = f; }); tick(); return fixture; } -function endSidenavTransition(fixture: ComponentFixture) { +function endSidenavTransition(fixture: ComponentFixture) { let sidenav: any = fixture.debugElement.query(By.directive(MdSidenav)).componentInstance; sidenav.onTransitionEnd({ target: (sidenav)._elementRef.nativeElement, diff --git a/src/components/sidenav/sidenav.ts b/src/components/sidenav/sidenav.ts index 6ac2f36dacea..8482baff6de6 100644 --- a/src/components/sidenav/sidenav.ts +++ b/src/components/sidenav/sidenav.ts @@ -1,29 +1,28 @@ import { - AfterContentInit, - Component, - ContentChildren, - ElementRef, - Host, - HostBinding, - HostListener, - Input, - Optional, - Output, - QueryList, - Type, - ChangeDetectionStrategy, - EventEmitter, - Renderer -} from 'angular2/core'; -import {BaseException} from 'angular2/src/facade/exceptions'; + AfterContentInit, + Component, + ContentChildren, + ElementRef, + Host, + HostBinding, + HostListener, + Input, + Optional, + Output, + QueryList, + Type, + ChangeDetectionStrategy, + EventEmitter, + Renderer +} from '@angular/core'; import {Dir} from '../../core/rtl/dir'; -import {PromiseCompleter} from 'angular2/src/facade/promise'; +import {PromiseCompleter} from '../../core/async/promise-completer'; /** * Exception thrown when two MdSidenav are matching the same side. */ -export class MdDuplicatedSidenavException extends BaseException { +export class MdDuplicatedSidenavError extends Error { constructor(align: string) { super(`A sidenav was already declared for 'align="${align}"'`); } @@ -307,12 +306,12 @@ export class MdSidenavLayout implements AfterContentInit { this._sidenavs.forEach(sidenav => { if (sidenav.align == 'end') { if (this._end != null) { - throw new MdDuplicatedSidenavException('end'); + throw new MdDuplicatedSidenavError('end'); } this._end = sidenav; } else { if (this._start != null) { - throw new MdDuplicatedSidenavException('start'); + throw new MdDuplicatedSidenavError('start'); } this._start = sidenav; } @@ -351,8 +350,8 @@ export class MdSidenavLayout implements AfterContentInit { /** * Return the width of the sidenav, if it's in the proper mode and opened. * This may relayout the view, so do not call this often. - * @param MdSidenav - * @private + * @param sidenav + * @param mode */ private _getSidenavEffectiveWidth(sidenav: MdSidenav, mode: string): number { return (this._isSidenavOpen(sidenav) && sidenav.mode == mode) ? sidenav._width : 0; diff --git a/src/components/toolbar/toolbar.spec.ts b/src/components/toolbar/toolbar.spec.ts index d385334d9bee..0970fe713741 100644 --- a/src/components/toolbar/toolbar.spec.ts +++ b/src/components/toolbar/toolbar.spec.ts @@ -1,13 +1,13 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import { it, describe, expect, beforeEach, inject, - TestComponentBuilder -} from 'angular2/testing'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; +import {By} from '@angular/platform-browser'; import {MdToolbar} from './toolbar'; export function main() { diff --git a/src/components/toolbar/toolbar.ts b/src/components/toolbar/toolbar.ts index fa36e3f357b3..2638a0066be8 100644 --- a/src/components/toolbar/toolbar.ts +++ b/src/components/toolbar/toolbar.ts @@ -2,9 +2,9 @@ import { Component, ChangeDetectionStrategy, Input -} from 'angular2/core'; -import {Renderer} from 'angular2/core'; -import {ElementRef} from 'angular2/core'; +} from '@angular/core'; +import {Renderer} from '@angular/core'; +import {ElementRef} from '@angular/core'; @Component({ selector: 'md-toolbar', diff --git a/src/core/async/promise-completer.ts b/src/core/async/promise-completer.ts new file mode 100644 index 000000000000..c205601e8433 --- /dev/null +++ b/src/core/async/promise-completer.ts @@ -0,0 +1,13 @@ + +export class PromiseCompleter { + promise: Promise; + resolve: (value?: R | PromiseLike) => void; + reject: (error?: any, stackTrace?: string) => void; + + constructor() { + this.promise = new Promise((res, rej) => { + this.resolve = res; + this.reject = rej; + }); + } +} diff --git a/src/core/gestures/MdGestureConfig.ts b/src/core/gestures/MdGestureConfig.ts index 21a7f295fb4f..a6c5d583e48d 100644 --- a/src/core/gestures/MdGestureConfig.ts +++ b/src/core/gestures/MdGestureConfig.ts @@ -1,5 +1,5 @@ -import {Injectable} from 'angular2/core'; -import {HammerGestureConfig} from 'angular2/src/platform/browser_common'; +import {Injectable} from '@angular/core'; +import {HammerGestureConfig} from '@angular/platform-browser'; /* Adjusts configuration of our gesture library, Hammer. */ @Injectable() diff --git a/src/core/live-announcer/live-announcer.spec.ts b/src/core/live-announcer/live-announcer.spec.ts index 46d8136617cb..20fd3ba29a39 100644 --- a/src/core/live-announcer/live-announcer.spec.ts +++ b/src/core/live-announcer/live-announcer.spec.ts @@ -4,16 +4,15 @@ import { expect, beforeEach, inject, - TestComponentBuilder, - ComponentFixture, fakeAsync, flushMicrotasks, tick, beforeEachProviders, getTestInjector -} from 'angular2/testing'; -import {Component, provide} from 'angular2/core'; -import {By} from 'angular2/platform/browser'; +} from '@angular/core/testing'; +import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; +import {Component, provide} from '@angular/core'; +import {By} from '@angular/platform-browser'; import {MdLiveAnnouncer, LIVE_ANNOUNCER_ELEMENT_TOKEN} from './live-announcer'; export function main() { @@ -38,7 +37,7 @@ export function main() { }); it('should correctly update the announce text', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + let appFixture: ComponentFixture = null; builder.createAsync(TestApp).then(fixture => { appFixture = fixture; @@ -58,7 +57,7 @@ export function main() { })); it('should correctly update the politeness attribute', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + let appFixture: ComponentFixture = null; builder.createAsync(TestApp).then(fixture => { appFixture = fixture; @@ -76,7 +75,7 @@ export function main() { })); it('should apply the aria-live value polite by default', fakeAsyncTest(() => { - let appFixture: ComponentFixture = null; + let appFixture: ComponentFixture = null; builder.createAsync(TestApp).then(fixture => { appFixture = fixture; diff --git a/src/core/live-announcer/live-announcer.ts b/src/core/live-announcer/live-announcer.ts index 51c02166f9a6..8af32e027add 100644 --- a/src/core/live-announcer/live-announcer.ts +++ b/src/core/live-announcer/live-announcer.ts @@ -3,7 +3,7 @@ import { OpaqueToken, Optional, Inject -} from 'angular2/core'; +} from '@angular/core'; export const LIVE_ANNOUNCER_ELEMENT_TOKEN = new OpaqueToken('mdLiveAnnouncerElement'); diff --git a/src/core/overlay/overlay.spec.ts b/src/core/overlay/overlay.spec.ts index 594cd88cecd9..48450b21d223 100644 --- a/src/core/overlay/overlay.spec.ts +++ b/src/core/overlay/overlay.spec.ts @@ -4,16 +4,16 @@ import { expect, beforeEach, inject, - TestComponentBuilder, fakeAsync, flushMicrotasks, beforeEachProviders, -} from 'angular2/testing'; +} from '@angular/core/testing'; +import {TestComponentBuilder} from '@angular/compiler/testing'; import { Component, ViewChild, provide, ViewContainerRef, -} from 'angular2/core'; +} from '@angular/core'; import {TemplatePortalDirective} from '../portal/portal-directives'; import {TemplatePortal, ComponentPortal} from '../portal/portal'; import {Overlay, OVERLAY_CONTAINER_TOKEN} from './overlay'; diff --git a/src/core/overlay/overlay.ts b/src/core/overlay/overlay.ts index 850b842f2bbe..8bcec53073fa 100644 --- a/src/core/overlay/overlay.ts +++ b/src/core/overlay/overlay.ts @@ -4,7 +4,7 @@ import { Inject, Injectable, ElementRef -} from 'angular2/core'; +} from '@angular/core'; import {OverlayState} from './overlay-state'; import {DomPortalHost} from '../portal/dom-portal-host'; import {OverlayRef} from './overlay-ref'; diff --git a/src/core/overlay/position/global-position-strategy.spec.ts b/src/core/overlay/position/global-position-strategy.spec.ts index 1d3123dbeddc..c1c541030efc 100644 --- a/src/core/overlay/position/global-position-strategy.spec.ts +++ b/src/core/overlay/position/global-position-strategy.spec.ts @@ -6,7 +6,7 @@ import { inject, fakeAsync, flushMicrotasks, -} from 'angular2/testing'; +} from '@angular/core/testing'; import {GlobalPositionStrategy} from './global-position-strategy'; diff --git a/src/core/overlay/position/relative-position-strategy.ts b/src/core/overlay/position/relative-position-strategy.ts index 337027a18cd8..4ae60d7b4a00 100644 --- a/src/core/overlay/position/relative-position-strategy.ts +++ b/src/core/overlay/position/relative-position-strategy.ts @@ -1,5 +1,5 @@ import {PositionStrategy} from './position-strategy'; -import {ElementRef} from 'angular2/core'; +import {ElementRef} from '@angular/core'; export class RelativePositionStrategy implements PositionStrategy { constructor(private _relativeTo: ElementRef) { } diff --git a/src/core/portal/dom-portal-host.ts b/src/core/portal/dom-portal-host.ts index bf0dff6981ad..737388b86778 100644 --- a/src/core/portal/dom-portal-host.ts +++ b/src/core/portal/dom-portal-host.ts @@ -1,6 +1,6 @@ -import {DynamicComponentLoader, ComponentRef, EmbeddedViewRef} from 'angular2/core'; +import {DynamicComponentLoader, ComponentRef, EmbeddedViewRef} from '@angular/core'; import {BasePortalHost, ComponentPortal, TemplatePortal} from './portal'; -import {MdComponentPortalAttachedToDomWithoutOriginException} from './portal-exceptions'; +import {MdComponentPortalAttachedToDomWithoutOriginError} from './portal-errors'; /** @@ -17,14 +17,14 @@ export class DomPortalHost extends BasePortalHost { } /** Attach the given ComponentPortal to DOM element using the DynamicComponentLoader. */ - attachComponentPortal(portal: ComponentPortal): Promise { + attachComponentPortal(portal: ComponentPortal): Promise> { if (portal.viewContainerRef == null) { - throw new MdComponentPortalAttachedToDomWithoutOriginException(); + throw new MdComponentPortalAttachedToDomWithoutOriginError(); } return this._componentLoader.loadNextToLocation( portal.component, portal.viewContainerRef).then(ref => { - let hostView = ref.hostView; + let hostView = > ref.hostView; this._hostDomElement.appendChild(hostView.rootNodes[0]); this.setDisposeFn(() => ref.destroy()); return ref; @@ -34,9 +34,6 @@ export class DomPortalHost extends BasePortalHost { attachTemplatePortal(portal: TemplatePortal): Promise> { let viewContainer = portal.viewContainerRef; let viewRef = viewContainer.createEmbeddedView(portal.templateRef); - // TODO(jelbourn): locals don't currently work with DomPortalHost; investigate whether there - // is a bug in Angular. - portal.locals.forEach((v, k) => viewRef.setLocal(k, v)); viewRef.rootNodes.forEach(rootNode => this._hostDomElement.appendChild(rootNode)); diff --git a/src/core/portal/portal-directives.ts b/src/core/portal/portal-directives.ts index a3ad916e2271..68780abb32d6 100644 --- a/src/core/portal/portal-directives.ts +++ b/src/core/portal/portal-directives.ts @@ -4,7 +4,7 @@ import { TemplateRef, DynamicComponentLoader, ViewContainerRef -} from 'angular2/core'; +} from '@angular/core'; import {Portal, TemplatePortal, ComponentPortal, BasePortalHost} from './portal'; @@ -23,7 +23,7 @@ import {Portal, TemplatePortal, ComponentPortal, BasePortalHost} from './portal' exportAs: 'portal', }) export class TemplatePortalDirective extends TemplatePortal { - constructor(templateRef: TemplateRef, viewContainerRef: ViewContainerRef) { + constructor(templateRef: TemplateRef, viewContainerRef: ViewContainerRef) { super(templateRef, viewContainerRef); } } @@ -59,7 +59,7 @@ export class PortalHostDirective extends BasePortalHost { } /** Attach the given ComponentPortal to this PortlHost using the DynamicComponentLoader. */ - attachComponentPortal(portal: ComponentPortal): Promise { + attachComponentPortal(portal: ComponentPortal): Promise> { portal.setAttachedHost(this); // If the portal specifies an origin, use that as the logical location of the component @@ -80,8 +80,7 @@ export class PortalHostDirective extends BasePortalHost { attachTemplatePortal(portal: TemplatePortal): Promise> { portal.setAttachedHost(this); - let viewRef = this._viewContainerRef.createEmbeddedView(portal.templateRef); - portal.locals.forEach((v, k) => viewRef.setLocal(k, v)); + this._viewContainerRef.createEmbeddedView(portal.templateRef); this.setDisposeFn(() => this._viewContainerRef.clear()); // TODO(jelbourn): return locals from view diff --git a/src/core/portal/portal-exceptions.ts b/src/core/portal/portal-errors.ts similarity index 71% rename from src/core/portal/portal-exceptions.ts rename to src/core/portal/portal-errors.ts index d30aa59e03eb..bef0ef3d7986 100644 --- a/src/core/portal/portal-exceptions.ts +++ b/src/core/portal/portal-errors.ts @@ -1,8 +1,5 @@ -import {BaseException} from 'angular2/src/facade/exceptions'; - - /** Exception thrown when a ComponentPortal is attached to a DomPortalHost without an origin. */ -export class MdComponentPortalAttachedToDomWithoutOriginException extends BaseException { +export class MdComponentPortalAttachedToDomWithoutOriginError extends Error { constructor() { super( 'A ComponentPortal must have an origin set when attached to a DomPortalHost ' + @@ -11,28 +8,28 @@ export class MdComponentPortalAttachedToDomWithoutOriginException extends BaseEx } /** Exception thrown when attmepting to attach a null portal to a host. */ -export class MdNullPortalException extends BaseException { +export class MdNullPortalError extends Error { constructor() { super('Must provide a portal to attach'); } } /** Exception thrown when attmepting to attach a portal to a host that is already attached. */ -export class MdPortalAlreadyAttachedException extends BaseException { +export class MdPortalAlreadyAttachedError extends Error { constructor() { super('Host already has a portal attached'); } } /** Exception thrown when attmepting to attach a portal to an already-disposed host. */ -export class MdPortalHostAlreadyDisposedException extends BaseException { +export class MdPortalHostAlreadyDisposedError extends Error { constructor() { super('This PortalHost has already been disposed'); } } /** Exception thrown when attmepting to attach an unknown portal type. */ -export class MdUnknownPortalTypeException extends BaseException { +export class MdUnknownPortalTypeErron extends Error { constructor() { super( 'Attempting to attach an unknown Portal type. ' + @@ -41,14 +38,14 @@ export class MdUnknownPortalTypeException extends BaseException { } /** Exception thrown when attmepting to attach a portal to a null host. */ -export class MdNullPortalHostException extends BaseException { +export class MdNullPortalHostError extends Error { constructor() { super('Attmepting to attach a portal to a null PortalHost'); } } /** Exception thrown when attmepting to detach a portal that is not attached. */ -export class MdNoPortalAttachedException extends BaseException { +export class MdNoPortalAttachedErron extends Error { constructor() { super('Attmepting to detach a portal that is not attached to a host'); } diff --git a/src/core/portal/portal.spec.ts b/src/core/portal/portal.spec.ts index e7e80d7e1eae..29b22ea8a62d 100644 --- a/src/core/portal/portal.spec.ts +++ b/src/core/portal/portal.spec.ts @@ -1,24 +1,25 @@ import { - it, - describe, - expect, - beforeEach, - inject, - ComponentFixture, - TestComponentBuilder, -} from 'angular2/testing'; -import {Component, ViewChildren, QueryList, ViewContainerRef} from 'angular2/core'; -import {TemplatePortalDirective} from './portal-directives'; -import {Portal} from './portal'; -import {ComponentPortal} from './portal'; -import {PortalHostDirective} from './portal-directives'; -import {fakeAsync} from 'angular2/testing'; -import {flushMicrotasks} from 'angular2/testing'; -import {DynamicComponentLoader} from 'angular2/core'; + it, + describe, + expect, + beforeEach, + inject, + fakeAsync, + flushMicrotasks +} from '@angular/core/testing'; +import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing'; +import { + Component, + ViewChildren, + QueryList, + ViewContainerRef, + DynamicComponentLoader +} from '@angular/core'; +import {TemplatePortalDirective, PortalHostDirective} from './portal-directives'; +import {Portal, ComponentPortal} from './portal'; import {DomPortalHost} from './dom-portal-host'; - export function main() { describe('Portals', () => { let builder: TestComponentBuilder; @@ -28,8 +29,8 @@ export function main() { })); describe('PortalHostDirective', () => { - it('should load a component into the portal', fakeAsyncTest(() => { - let appFixture: ComponentFixture; + it('should load a component into the portal', fakeAsync(() => { + let appFixture: ComponentFixture; builder.createAsync(PortalTestApp).then(fixture => { appFixture = fixture; @@ -51,8 +52,8 @@ export function main() { expect(hostContainer.textContent).toContain('Pizza'); })); - it('should load a
Pie
- - `, directives: [PortalHostDirective, TemplatePortalDirective], }) @@ -392,12 +360,4 @@ class PortalTestApp { get portalWithBinding() { return this.portals.toArray()[2]; } - - get portalWithLocals() { - return this.portals.last; - } -} - -function fakeAsyncTest(fn: () => void) { - return inject([], fakeAsync(fn)); } diff --git a/src/core/portal/portal.ts b/src/core/portal/portal.ts index 971e8b394cde..b34c1f82530a 100644 --- a/src/core/portal/portal.ts +++ b/src/core/portal/portal.ts @@ -1,15 +1,12 @@ -import {TemplateRef, Type, ViewContainerRef} from 'angular2/core'; -import {ElementRef} from 'angular2/core'; -import {ComponentRef} from 'angular2/core'; - +import {TemplateRef, Type, ViewContainerRef, ElementRef, ComponentRef} from '@angular/core'; import { - MdNullPortalHostException, - MdPortalAlreadyAttachedException, - MdNoPortalAttachedException, - MdNullPortalException, - MdPortalHostAlreadyDisposedException, - MdUnknownPortalTypeException -} from './portal-exceptions'; + MdNullPortalHostError, + MdPortalAlreadyAttachedError, + MdNoPortalAttachedErron, + MdNullPortalError, + MdPortalHostAlreadyDisposedError, + MdUnknownPortalTypeErron +} from './portal-errors'; /** @@ -22,11 +19,11 @@ export abstract class Portal { /** Attach this portal to a host. */ attach(host: PortalHost): Promise { if (host == null) { - throw new MdNullPortalHostException(); + throw new MdNullPortalHostError(); } if (host.hasAttached()) { - throw new MdPortalAlreadyAttachedException(); + throw new MdPortalAlreadyAttachedError(); } this._attachedHost = host; @@ -37,7 +34,7 @@ export abstract class Portal { detach(): Promise { let host = this._attachedHost; if (host == null) { - throw new MdNoPortalAttachedException(); + throw new MdNoPortalAttachedErron(); } this._attachedHost = null; @@ -62,7 +59,7 @@ export abstract class Portal { /** * A `ComponentPortal` is a portal that instantiates some Component upon attachment. */ -export class ComponentPortal extends Portal { +export class ComponentPortal extends Portal> { /** The type of the component that will be instantiated for attachment. */ public component: Type; @@ -86,7 +83,7 @@ export class ComponentPortal extends Portal { */ export class TemplatePortal extends Portal> { /** The embedded template that will be used to instantiate an embedded View in the host. */ - templateRef: TemplateRef; + templateRef: TemplateRef; /** Reference to the ViewContainer into which the template will be stamped out. */ viewContainerRef: ViewContainerRef; @@ -99,7 +96,7 @@ export class TemplatePortal extends Portal> { */ locals: Map = new Map(); - constructor(template: TemplateRef, viewContainerRef: ViewContainerRef) { + constructor(template: TemplateRef, viewContainerRef: ViewContainerRef) { super(); this.templateRef = template; this.viewContainerRef = viewContainerRef; @@ -156,15 +153,15 @@ export abstract class BasePortalHost implements PortalHost { attach(portal: Portal): Promise { if (portal == null) { - throw new MdNullPortalException(); + throw new MdNullPortalError(); } if (this.hasAttached()) { - throw new MdPortalAlreadyAttachedException(); + throw new MdPortalAlreadyAttachedError(); } if (this._isDisposed) { - throw new MdPortalHostAlreadyDisposedException(); + throw new MdPortalHostAlreadyDisposedError(); } if (portal instanceof ComponentPortal) { @@ -175,10 +172,10 @@ export abstract class BasePortalHost implements PortalHost { return this.attachTemplatePortal(portal); } - throw new MdUnknownPortalTypeException(); + throw new MdUnknownPortalTypeErron(); } - abstract attachComponentPortal(portal: ComponentPortal): Promise; + abstract attachComponentPortal(portal: ComponentPortal): Promise>; abstract attachTemplatePortal(portal: TemplatePortal): Promise>; diff --git a/src/core/rtl/dir.ts b/src/core/rtl/dir.ts index d21757a0c02c..6c7f80ee0293 100644 --- a/src/core/rtl/dir.ts +++ b/src/core/rtl/dir.ts @@ -1,4 +1,4 @@ -import {Directive, HostBinding, Output, Input, EventEmitter} from 'angular2/core'; +import {Directive, HostBinding, Output, Input, EventEmitter} from '@angular/core'; export type LayoutDirection = 'ltr' | 'rtl'; diff --git a/src/demo-app/button/button-demo.ts b/src/demo-app/button/button-demo.ts index 07aedc1ac3f7..9f591b02144b 100644 --- a/src/demo-app/button/button-demo.ts +++ b/src/demo-app/button/button-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton, MdAnchor} from '../../components/button/button'; import {MdIcon} from '../../components/icon/icon'; diff --git a/src/demo-app/card/card-demo.ts b/src/demo-app/card/card-demo.ts index 9ff44a12bd2f..8eaf7801bfab 100644 --- a/src/demo-app/card/card-demo.ts +++ b/src/demo-app/card/card-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton} from '../../components/button/button'; import {MD_CARD_DIRECTIVES} from '../../components/card/card'; diff --git a/src/demo-app/checkbox/checkbox-demo.html b/src/demo-app/checkbox/checkbox-demo.html index b811f6969563..f7629fc9345c 100644 --- a/src/demo-app/checkbox/checkbox-demo.html +++ b/src/demo-app/checkbox/checkbox-demo.html @@ -1,11 +1,15 @@

md-checkbox: Basic Example

+
Do you want to foobar the bazquux? + - {{printResult()}} +
- Button - Card - Checkbox - Gestures - Grid List - Icon - Input - List - Live Announcer - Overlay - Portal - Progress Circle - Progress Bar - Radio - Sidenav - Toolbar + Button + Card + Checkbox + Gestures + Grid List + Icon + Input + List + Live Announcer + Overlay + Portal + Progress Circle + Progress Bar + Radio + Sidenav + Toolbar diff --git a/src/demo-app/demo-app.ts b/src/demo-app/demo-app.ts index 112acd31fac2..4e63e2206f48 100644 --- a/src/demo-app/demo-app.ts +++ b/src/demo-app/demo-app.ts @@ -1,5 +1,5 @@ -import {Component} from 'angular2/core'; -import {Route, RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; +import {Component} from '@angular/core'; +import {Route, Routes, ROUTER_DIRECTIVES} from '@angular/router'; import {CardDemo} from './card/card-demo'; import {ButtonDemo} from './button/button-demo'; import {IconDemo} from './icon/icon-demo'; @@ -48,23 +48,23 @@ export class Home {} ], pipes: [] }) -@RouteConfig([ - new Route({path: '/', name: 'Home', component: Home, useAsDefault: true}), - new Route({path: '/button', name: 'ButtonDemo', component: ButtonDemo}), - new Route({path: '/card', name: 'CardDemo', component: CardDemo}), - new Route({path: '/radio', name: 'RadioDemo', component: RadioDemo}), - new Route({path: '/sidenav', name: 'SidenavDemo', component: SidenavDemo}), - new Route({path: '/progress-circle', name: 'ProgressCircleDemo', component: ProgressCircleDemo}), - new Route({path: '/progress-bar', name: 'ProgressBarDemo', component: ProgressBarDemo}), - new Route({path: '/portal', name: 'PortalDemo', component: PortalDemo}), - new Route({path: '/overlay', name: 'OverlayDemo', component: OverlayDemo}), - new Route({path: '/checkbox', name: 'CheckboxDemo', component: CheckboxDemo}), - new Route({path: '/input', name: 'InputDemo', component: InputDemo}), - new Route({path: '/toolbar', name: 'ToolbarDemo', component: ToolbarDemo}), - new Route({path: '/icon', name: 'IconDemo', component: IconDemo}), - new Route({path: '/list', name: 'ListDemo', component: ListDemo}), - new Route({path: '/live-announcer', name: 'LiveAnnouncerDemo', component: LiveAnnouncerDemo}), - new Route({path: '/gestures', name: 'GesturesDemo', component: GesturesDemo}), - new Route({path: '/grid-list', name: 'GridListDemo', component: GridListDemo}), +@Routes([ + new Route({path: '/', component: Home}), + new Route({path: '/button', component: ButtonDemo}), + new Route({path: '/card', component: CardDemo}), + new Route({path: '/radio', component: RadioDemo}), + new Route({path: '/sidenav', component: SidenavDemo}), + new Route({path: '/progress-circle', component: ProgressCircleDemo}), + new Route({path: '/progress-bar', component: ProgressBarDemo}), + new Route({path: '/portal', component: PortalDemo}), + new Route({path: '/overlay', component: OverlayDemo}), + new Route({path: '/checkbox', component: CheckboxDemo}), + new Route({path: '/input', component: InputDemo}), + new Route({path: '/toolbar', component: ToolbarDemo}), + new Route({path: '/icon', component: IconDemo}), + new Route({path: '/list', component: ListDemo}), + new Route({path: '/live-announcer', component: LiveAnnouncerDemo}), + new Route({path: '/gestures', component: GesturesDemo}), + new Route({path: '/grid-list', component: GridListDemo}), ]) export class DemoApp { } diff --git a/src/demo-app/gestures/gestures-demo.ts b/src/demo-app/gestures/gestures-demo.ts index 87f93d82b656..70c27d455af1 100644 --- a/src/demo-app/gestures/gestures-demo.ts +++ b/src/demo-app/gestures/gestures-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; @Component({ selector: 'gestures-demo', diff --git a/src/demo-app/grid-list/grid-list-demo.ts b/src/demo-app/grid-list/grid-list-demo.ts index 66480507d7ff..17892c52938a 100644 --- a/src/demo-app/grid-list/grid-list-demo.ts +++ b/src/demo-app/grid-list/grid-list-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdGridList} from '../../components/grid-list/grid-list'; @Component({ diff --git a/src/demo-app/icon/icon-demo.ts b/src/demo-app/icon/icon-demo.ts index ae29dbedbd2b..c7df43059906 100644 --- a/src/demo-app/icon/icon-demo.ts +++ b/src/demo-app/icon/icon-demo.ts @@ -1,4 +1,4 @@ -import {Component, ViewEncapsulation} from 'angular2/core'; +import {Component, ViewEncapsulation} from '@angular/core'; import {MdIcon} from '../../components/icon/icon'; import {MdIconRegistry} from '../../components/icon/icon-registry'; diff --git a/src/demo-app/input/input-demo.ts b/src/demo-app/input/input-demo.ts index b0c74263a981..1b46610e9b20 100644 --- a/src/demo-app/input/input-demo.ts +++ b/src/demo-app/input/input-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MD_INPUT_DIRECTIVES} from '../../components/input/input'; import {MdButton} from '../../components/button/button'; import {MdCard} from '../../components/card/card'; diff --git a/src/demo-app/list/list-demo.ts b/src/demo-app/list/list-demo.ts index 3462da4a8b20..f24d2a63728e 100644 --- a/src/demo-app/list/list-demo.ts +++ b/src/demo-app/list/list-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton} from '../../components/button/button'; import {MD_LIST_DIRECTIVES} from '../../components/list/list'; import {MdIcon} from '../../components/icon/icon'; diff --git a/src/demo-app/live-announcer/live-announcer-demo.ts b/src/demo-app/live-announcer/live-announcer-demo.ts index e5b381749a9e..377438c6201a 100644 --- a/src/demo-app/live-announcer/live-announcer-demo.ts +++ b/src/demo-app/live-announcer/live-announcer-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdLiveAnnouncer} from '../../core/live-announcer/live-announcer'; @Component({ diff --git a/src/demo-app/overlay/overlay-demo.ts b/src/demo-app/overlay/overlay-demo.ts index 601251b3a8ea..4e0c369e2b60 100644 --- a/src/demo-app/overlay/overlay-demo.ts +++ b/src/demo-app/overlay/overlay-demo.ts @@ -1,7 +1,7 @@ import { Component, ViewChildren, QueryList, ViewEncapsulation, ViewContainerRef -} from 'angular2/core'; +} from '@angular/core'; import { Overlay, OverlayState} from '../../core/overlay/overlay'; diff --git a/src/demo-app/portal/portal-demo.ts b/src/demo-app/portal/portal-demo.ts index 2ea7d81adf00..65a5e0980769 100644 --- a/src/demo-app/portal/portal-demo.ts +++ b/src/demo-app/portal/portal-demo.ts @@ -1,9 +1,9 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {PortalHostDirective} from '../../core/portal/portal-directives'; import {TemplatePortalDirective} from '../../core/portal/portal-directives'; import {Portal} from '../../core/portal/portal'; -import {ViewChildren} from 'angular2/core'; -import {QueryList} from 'angular2/core'; +import {ViewChildren} from '@angular/core'; +import {QueryList} from '@angular/core'; import {ComponentPortal} from '../../core/portal/portal'; @Component({ diff --git a/src/demo-app/progress-bar/progress-bar-demo.ts b/src/demo-app/progress-bar/progress-bar-demo.ts index 72162a5ff854..04a54c839532 100644 --- a/src/demo-app/progress-bar/progress-bar-demo.ts +++ b/src/demo-app/progress-bar/progress-bar-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton} from '../../components/button/button'; import {MdProgressBar} from '../../components/progress-bar/progress-bar'; diff --git a/src/demo-app/progress-circle/progress-circle-demo.ts b/src/demo-app/progress-circle/progress-circle-demo.ts index c9cb567ca036..4b50fe6e2928 100644 --- a/src/demo-app/progress-circle/progress-circle-demo.ts +++ b/src/demo-app/progress-circle/progress-circle-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton} from '../../components/button/button'; import {MdProgressCircle, MdSpinner} from '../../components/progress-circle/progress-circle'; diff --git a/src/demo-app/radio/radio-demo.ts b/src/demo-app/radio/radio-demo.ts index 3eaa7ee911ce..f5c13f5fc731 100644 --- a/src/demo-app/radio/radio-demo.ts +++ b/src/demo-app/radio/radio-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdRadioButton, MdRadioGroup} from '../../components/radio/radio'; import {MdRadioDispatcher} from '../../components/radio/radio_dispatcher'; diff --git a/src/demo-app/sidenav/sidenav-demo.ts b/src/demo-app/sidenav/sidenav-demo.ts index 5f5d606cfcae..135ba46b94a1 100644 --- a/src/demo-app/sidenav/sidenav-demo.ts +++ b/src/demo-app/sidenav/sidenav-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdButton} from '../../components/button/button'; import {MD_SIDENAV_DIRECTIVES} from '../../components/sidenav/sidenav'; diff --git a/src/demo-app/toolbar/toolbar-demo.ts b/src/demo-app/toolbar/toolbar-demo.ts index a2bfedcea988..0aefbb60125c 100644 --- a/src/demo-app/toolbar/toolbar-demo.ts +++ b/src/demo-app/toolbar/toolbar-demo.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import {Component} from '@angular/core'; import {MdIcon} from '../../components/icon/icon'; import {MdToolbar} from '../../components/toolbar/toolbar'; diff --git a/src/index.html b/src/index.html index dc88807a9014..f5f78283e30a 100644 --- a/src/index.html +++ b/src/index.html @@ -5,44 +5,30 @@ Material2 - - - {{content-for 'head'}} + Loading... + + + + - - - - + + diff --git a/src/main.ts b/src/main.ts index ade68ee21211..babe0c1e1c58 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,14 +1,14 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {HAMMER_GESTURE_CONFIG} from 'angular2/src/platform/browser_common'; +import {bootstrap} from '@angular/platform-browser-dynamic'; +import {HAMMER_GESTURE_CONFIG} from '@angular/platform-browser'; import {DemoApp} from './demo-app/demo-app'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {ROUTER_PROVIDERS} from 'angular2/router'; +import {HTTP_PROVIDERS} from '@angular/http'; +import {ROUTER_PROVIDERS} from '@angular/router'; import {MdIconRegistry} from './components/icon/icon-registry'; import {OVERLAY_CONTAINER_TOKEN} from './core/overlay/overlay'; import {MdLiveAnnouncer} from './core/live-announcer/live-announcer'; -import {provide} from 'angular2/core'; +import {provide} from '@angular/core'; import {createOverlayContainer} from './core/overlay/overlay-container'; -import {Renderer} from 'angular2/core'; +import {Renderer} from '@angular/core'; import {MdGestureConfig} from './core/gestures/MdGestureConfig'; import 'rxjs/Rx'; diff --git a/src/system-config.ts b/src/system-config.ts new file mode 100644 index 000000000000..5a7d5f604a97 --- /dev/null +++ b/src/system-config.ts @@ -0,0 +1,66 @@ +/*********************************************************************************************** + * User Configuration. + **********************************************************************************************/ +/** Map relative paths to URLs. */ +const map: any = { +}; + +/** User packages configuration. */ +const packages: any = { + 'demo-app': { + format: 'cjs', + defaultExtension: 'js' + }, + 'components': { + format: 'cjs', + defaultExtension: 'js' + }, + 'core': { + format: 'cjs', + defaultExtension: 'js' + }, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////// +/*********************************************************************************************** + * Everything underneath this line is managed by the CLI. + **********************************************************************************************/ +const barrels: string[] = [ + // Angular specific barrels. + '@angular/core', + '@angular/common', + '@angular/compiler', + '@angular/http', + '@angular/router', + '@angular/platform-browser', + '@angular/platform-browser-dynamic', + + // Thirdparty barrels. + 'rxjs', + + // App specific barrels. + 'app', + 'app/shared', + /** @cli-barrel */ +]; + +const _cliSystemConfig = {}; +barrels.forEach((barrelName: string) => { + ( _cliSystemConfig)[barrelName] = { main: 'index' }; +}); + +/** Type declaration for ambient System. */ +declare var System: any; + +// Apply the CLI SystemJS configuration. +System.config({ + map: { + '@angular': 'vendor/@angular', + 'rxjs': 'vendor/rxjs', + 'main': 'main.js' + }, + packages: _cliSystemConfig +}); + +// Apply the user's configuration. +System.config({ map, packages }); diff --git a/test/karma-test-shim.js b/test/karma-test-shim.js index 63afe69caf15..e0809e59ed33 100644 --- a/test/karma-test-shim.js +++ b/test/karma-test-shim.js @@ -1,91 +1,57 @@ +/*global jasmine, __karma__, window*/ Error.stackTraceLimit = Infinity; +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; -jasmine.DEFAULT_TIMEOUT_INTERVAL = 4000; +__karma__.loaded = function () { +}; -__karma__.loaded = function() {}; +var distPath = '/base/dist/'; - -/** - * Gets map of module alias to location or package. - * @param dir Directory name under `src/` for create a map for. - */ -function getPathsMap(dir) { - return Object.keys(window.__karma__.files) - .filter(not(isSpecFile)) - .filter(function(x) { return new RegExp('^/base/dist/' + dir + '/.*\\.js$').test(x); }) - .reduce(function(pathsMapping, appPath) { - var pathToReplace = new RegExp('^/base/dist/' + dir + '/'); - var moduleName = appPath.replace(pathToReplace, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]; - return pathsMapping; - }, {}); +function isJsFile(path) { + return path.slice(-3) == '.js'; } -System.config({ - packages: { - 'base/dist/components': { - defaultExtension: false, - format: 'cjs', - map: getPathsMap('components') - }, - 'base/dist/core': { - defaultExtension: false, - format: 'cjs', - map: getPathsMap('core') - }, - } -}); +function isSpecFile(path) { + return path.slice(-8) == '.spec.js'; +} +function isMaterialFile(path) { + return isJsFile(path) && path.indexOf('vendor') == -1; +} -/** - * Bootstrap the browser testing providers from Angular2. The equivalent code in TypeScript - * would be: - * - * - * import {setBaseTestProviders} from 'angular2/testing'; - * import * as browser from 'angular2/platform/testing/browser'; - * - * setBaseTestProviders(browser.TEST_BROWSER_PLATFORM_PROVIDERS, - * browser.TEST_BROWSER_APPLICATION_PROVIDERS); - * - * - * See https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta2-2016-01-28 - * - * Followed by the normal import of all spec files, then bootstrap Karma. - */ -Promise.all([ - System.import('angular2/testing'), - System.import('angular2/platform/testing/browser'), -]).then(function(imports) { - var testing = imports[0]; - var browser = imports[1]; - testing.setBaseTestProviders(browser.TEST_BROWSER_PLATFORM_PROVIDERS, - browser.TEST_BROWSER_APPLICATION_PROVIDERS); +var allSpecFiles = Object.keys(window.__karma__.files) + .filter(isSpecFile) + .filter(isMaterialFile); - return Promise.all( - Object.keys(window.__karma__.files) - .filter(isSpecFile) - .map(function(moduleName) { - return System.import(moduleName).then(function(module) { - if (module.hasOwnProperty('main')) { - return module.main(); - } else { - return module; - } - }); - })); -}).then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); +// Load our SystemJS configuration. +System.config({ + baseURL: distPath }); -function isSpecFile(path) { - return /\.spec\.js$/.test(path); -} - -function not(fn) { - return function() { - return !fn.apply(this, arguments); - }; -} +System.import('system-config.js').then(function() { + // Load and configure the TestComponentBuilder. + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]).then(function (providers) { + var testing = providers[0]; + var testingBrowser = providers[1]; + + testing.setBaseTestProviders(testingBrowser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, + testingBrowser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS); + }); +}).then(function() { + // Finally, load all spec files. + // This will run the tests directly. + return Promise.all( + allSpecFiles.map(function (moduleName) { + return System.import(moduleName).then(function(module) { + // TODO(jelbourn): remove `main` method from tests and this check. + if (module.hasOwnProperty('main')) { + return module.main(); + } else { + return module; + } + }); + })); +}).then(__karma__.start, __karma__.error); diff --git a/test/karma.config.ts b/test/karma.config.ts index 82a5957b9ae4..f59485659c5b 100644 --- a/test/karma.config.ts +++ b/test/karma.config.ts @@ -19,22 +19,13 @@ export function config(config) { require('karma-firefox-launcher'), ], files: [ - {pattern: 'node_modules/es6-shim/es6-shim.min.js', included: true, watched: false}, - {pattern: 'node_modules/systemjs/dist/system-polyfills.js', included: true, watched: false}, - 'node_modules/angular2/es6/dev/src/testing/shims_for_IE.js', - - // Angular 2 polyfills *must* be loaded after es6-shim and system-polyfills in order to - // setup the monkey-patches for zones. - {pattern: 'node_modules/angular2/bundles/angular2-polyfills.js', included: true, watched: false}, - {pattern: 'node_modules/zone.js/dist/jasmine-patch.js', included: true, watched: false}, - {pattern: 'node_modules/zone.js/dist/async-test.js', included: true, watched: false}, - {pattern: 'node_modules/zone.js/dist/fake-async-test.js', included: true, watched: false}, - {pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: false}, - {pattern: 'node_modules/rxjs/bundles/Rx.js', included: true, watched: false}, - 'node_modules/reflect-metadata/Reflect.js', - {pattern: 'node_modules/angular2/bundles/angular2.dev.js', included: true, watched: false}, - {pattern: 'node_modules/angular2/bundles/http.dev.js', included: true, watched: false}, - {pattern: 'node_modules/angular2/bundles/testing.dev.js', included: true, watched: false}, + {pattern: 'dist/vendor/es6-shim/es6-shim.js', included: true, watched: false}, + {pattern: 'dist/vendor/reflect-metadata/Reflect.js', included: true, watched: false}, + {pattern: 'dist/vendor/systemjs/dist/system-polyfills.js', included: true, watched: false}, + {pattern: 'dist/vendor/systemjs/dist/system.src.js', included: true, watched: false}, + {pattern: 'dist/vendor/zone.js/dist/zone.js', included: true, watched: false}, + {pattern: 'dist/vendor/zone.js/dist/async-test.js', included: true, watched: false}, + {pattern: 'dist/vendor/zone.js/dist/fake-async-test.js', included: true, watched: false}, {pattern: 'test/karma-test-shim.js', included: true, watched: true}, @@ -52,10 +43,8 @@ export function config(config) { ], proxies: { // required for component assests fetched by Angular's compiler - '/demo-app/': '/base/dist/demo-app/', '/components/': '/base/dist/components/', '/core/': '/base/dist/core/', - '/directives/': '/base/dist/directives/', }, customLaunchers: customLaunchers,