From 97c212f23c298ea622df1015672fc334417a08e8 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 5 Jan 2017 16:09:03 -0800 Subject: [PATCH 01/19] date picker initial commit --- .../date-picker/date-picker-demo.html | 1 + src/demo-app/date-picker/date-picker-demo.ts | 10 ++++++++++ src/demo-app/demo-app-module.ts | 2 ++ src/demo-app/demo-app/demo-app.ts | 1 + src/demo-app/demo-app/routes.ts | 2 ++ src/lib/date-picker/index.ts | 19 +++++++++++++++++++ src/lib/date-picker/month-view.html | 1 + src/lib/date-picker/month-view.scss | 3 +++ src/lib/date-picker/month-view.ts | 14 ++++++++++++++ src/lib/index.ts | 1 + src/lib/module.ts | 3 +++ 11 files changed, 57 insertions(+) create mode 100644 src/demo-app/date-picker/date-picker-demo.html create mode 100644 src/demo-app/date-picker/date-picker-demo.ts create mode 100644 src/lib/date-picker/index.ts create mode 100644 src/lib/date-picker/month-view.html create mode 100644 src/lib/date-picker/month-view.scss create mode 100644 src/lib/date-picker/month-view.ts diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/date-picker/date-picker-demo.html new file mode 100644 index 000000000000..54dfea6858d5 --- /dev/null +++ b/src/demo-app/date-picker/date-picker-demo.html @@ -0,0 +1 @@ + diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts new file mode 100644 index 000000000000..804ab2919c44 --- /dev/null +++ b/src/demo-app/date-picker/date-picker-demo.ts @@ -0,0 +1,10 @@ +import {Component} from '@angular/core'; + + +@Component({ + moduleId: module.id, + selector: 'date-picker-demo', + templateUrl: 'date-picker-demo.html', + styleUrls: ['date-picker-demo.css'] +}) +export class DatePickerDemo {} diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts index 47b54dbb1036..786bd1aaa4fe 100644 --- a/src/demo-app/demo-app-module.ts +++ b/src/demo-app/demo-app-module.ts @@ -38,6 +38,7 @@ import {ProjectionDemo, ProjectionTestComponent} from './projection/projection-d import {PlatformDemo} from './platform/platform-demo'; import {AutocompleteDemo} from './autocomplete/autocomplete-demo'; import {InputContainerDemo} from './input/input-container-demo'; +import {DatePickerDemo} from './date-picker/date-picker-demo'; @NgModule({ imports: [ @@ -56,6 +57,7 @@ import {InputContainerDemo} from './input/input-container-demo'; CardDemo, ChipsDemo, CheckboxDemo, + DatePickerDemo, DemoApp, DialogDemo, GesturesDemo, diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 98c029d770cc..3111c9515bfd 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -26,6 +26,7 @@ export class DemoApp { {name: 'Card', route: 'card'}, {name: 'Chips', route: 'chips'}, {name: 'Checkbox', route: 'checkbox'}, + {name: 'Date Picker', route: 'date-picker'}, {name: 'Dialog', route: 'dialog'}, {name: 'Gestures', route: 'gestures'}, {name: 'Grid List', route: 'grid-list'}, diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts index 3a1b3ba916b6..7319643021f8 100644 --- a/src/demo-app/demo-app/routes.ts +++ b/src/demo-app/demo-app/routes.ts @@ -32,6 +32,7 @@ import {TABS_DEMO_ROUTES} from '../tabs/routes'; import {PlatformDemo} from '../platform/platform-demo'; import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; import {InputContainerDemo} from '../input/input-container-demo'; +import {DatePickerDemo} from '../date-picker/date-picker-demo'; export const DEMO_APP_ROUTES: Routes = [ {path: '', component: Home}, @@ -39,6 +40,7 @@ export const DEMO_APP_ROUTES: Routes = [ {path: 'button', component: ButtonDemo}, {path: 'card', component: CardDemo}, {path: 'chips', component: ChipsDemo}, + {path: 'date-picker', component: DatePickerDemo}, {path: 'radio', component: RadioDemo}, {path: 'select', component: SelectDemo}, {path: 'sidenav', component: SidenavDemo}, diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts new file mode 100644 index 000000000000..4e9a442f489e --- /dev/null +++ b/src/lib/date-picker/index.ts @@ -0,0 +1,19 @@ +import {ModuleWithProviders, NgModule} from '@angular/core'; +import {MdMonthView} from './month-view'; +import {DefaultStyleCompatibilityModeModule} from '../core/compatibility/default-mode'; + +export * from './month-view'; + +@NgModule({ + imports: [DefaultStyleCompatibilityModeModule], + exports: [MdMonthView, DefaultStyleCompatibilityModeModule], + declarations: [MdMonthView], +}) +export class MdDatePickerModule { + static forRoot(): ModuleWithProviders { + return { + ngModule: MdDatePickerModule, + providers: [] + }; + } +} diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html new file mode 100644 index 000000000000..2c1abb312d40 --- /dev/null +++ b/src/lib/date-picker/month-view.html @@ -0,0 +1 @@ +I'm a month diff --git a/src/lib/date-picker/month-view.scss b/src/lib/date-picker/month-view.scss new file mode 100644 index 000000000000..a3fe87387991 --- /dev/null +++ b/src/lib/date-picker/month-view.scss @@ -0,0 +1,3 @@ +md-month-view { + background: red; +} diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts new file mode 100644 index 000000000000..c6ad93fecb1a --- /dev/null +++ b/src/lib/date-picker/month-view.ts @@ -0,0 +1,14 @@ +import {Component, ViewEncapsulation, ChangeDetectionStrategy, Input} from '@angular/core'; + + +@Component({ + moduleId: module.id, + selector: 'md-month-view, mat-month-view', + templateUrl: 'month-view.html', + styleUrls: ['month-view.css'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MdMonthView { + @Input() date: Date; +} diff --git a/src/lib/index.ts b/src/lib/index.ts index 2e09d36df567..24420b24504c 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -6,6 +6,7 @@ export * from './button-toggle/index'; export * from './card/index'; export * from './chips/index'; export * from './checkbox/index'; +export * from './date-picker/index'; export * from './dialog/index'; export * from './grid-list/index'; export * from './icon/index'; diff --git a/src/lib/module.ts b/src/lib/module.ts index fdfa6b1922db..15065a9d1356 100644 --- a/src/lib/module.ts +++ b/src/lib/module.ts @@ -36,6 +36,7 @@ import {MdMenuModule} from './menu/index'; import {MdDialogModule} from './dialog/index'; import {PlatformModule} from './core/platform/index'; import {MdAutocompleteModule} from './autocomplete/index'; +import {MdDatePickerModule} from './date-picker/index'; const MATERIAL_MODULES = [ MdAutocompleteModule, @@ -44,6 +45,7 @@ const MATERIAL_MODULES = [ MdCardModule, MdChipsModule, MdCheckboxModule, + MdDatePickerModule, MdDialogModule, MdGridListModule, MdIconModule, @@ -80,6 +82,7 @@ const MATERIAL_MODULES = [ MdCardModule.forRoot(), MdChipsModule.forRoot(), MdCheckboxModule.forRoot(), + MdDatePickerModule.forRoot(), MdGridListModule.forRoot(), MdInputModule.forRoot(), MdListModule.forRoot(), From 304f4e4f81e183fcbbccad6d30a97e9b331651b2 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 5 Jan 2017 17:31:23 -0800 Subject: [PATCH 02/19] month view --- src/lib/date-picker/index.ts | 3 +- src/lib/date-picker/month-view.html | 9 +++++- src/lib/date-picker/month-view.ts | 47 ++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts index 4e9a442f489e..afcc8b5d9132 100644 --- a/src/lib/date-picker/index.ts +++ b/src/lib/date-picker/index.ts @@ -1,11 +1,12 @@ import {ModuleWithProviders, NgModule} from '@angular/core'; import {MdMonthView} from './month-view'; import {DefaultStyleCompatibilityModeModule} from '../core/compatibility/default-mode'; +import {CommonModule} from '@angular/common'; export * from './month-view'; @NgModule({ - imports: [DefaultStyleCompatibilityModeModule], + imports: [CommonModule, DefaultStyleCompatibilityModeModule], exports: [MdMonthView, DefaultStyleCompatibilityModeModule], declarations: [MdMonthView], }) diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index 2c1abb312d40..57e530675038 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -1 +1,8 @@ -I'm a month + + + + + + + +
{{label}}
{{getDateString(date)}}
diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index c6ad93fecb1a..54b549c90227 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -10,5 +10,50 @@ import {Component, ViewEncapsulation, ChangeDetectionStrategy, Input} from '@ang changeDetection: ChangeDetectionStrategy.OnPush, }) export class MdMonthView { - @Input() date: Date; + @Input() date: Date = new Date(); + + localeSettings = { + firstDayOfWeek: 0, + getDateString: (d: number) => '' + d, + getMonthLabel: (m: number, y: number) => { + let months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUL', 'AUG', 'SEP', 'OCT', 'DEC']; + return `${months[m]} ${y}`; + } + }; + + label: string; + + weeks: number[][]; + + padding: number; + + constructor() { + this.label = this.localeSettings.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); + this._calculateWeeks(); + } + + private _calculateWeeks() { + let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); + let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); + let padding = (7 + firstOfMonth.getDay() - this.localeSettings.firstDayOfWeek) % 7; + + // Fill in empty cells at the beginning of the month. + this.weeks = [[]]; + for (let i = 0; i < padding; i++) { + this.weeks[0].push(0); + } + + // Fill in the date cells. + for (let i = 0, cell = padding; i < daysInMonth; i++, cell++) { + if (cell == 7) { + this.weeks.push([]); + cell = 0; + } + this.weeks[this.weeks.length - 1].push(i + 1); + } + } + + getDateString(date: number) { + return date == 0 ? '' : this.localeSettings.getDateString(date); + } } From 35ec1a5b8e8346dcd42ebc2a9989c2edae4f2229 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Fri, 6 Jan 2017 16:33:20 -0800 Subject: [PATCH 03/19] added month view functionality --- .../date-picker/date-picker-demo.html | 3 +- src/demo-app/date-picker/date-picker-demo.ts | 5 +- src/lib/core/coercion/date-property.ts | 5 + src/lib/core/theming/_all-theme.scss | 2 + src/lib/date-picker/_date-picker-theme.scss | 32 +++++++ src/lib/date-picker/month-view.html | 33 ++++++- src/lib/date-picker/month-view.scss | 34 ++++++- src/lib/date-picker/month-view.ts | 93 +++++++++++++------ 8 files changed, 172 insertions(+), 35 deletions(-) create mode 100644 src/lib/core/coercion/date-property.ts create mode 100644 src/lib/date-picker/_date-picker-theme.scss diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/date-picker/date-picker-demo.html index 54dfea6858d5..22b931de17e2 100644 --- a/src/demo-app/date-picker/date-picker-demo.html +++ b/src/demo-app/date-picker/date-picker-demo.html @@ -1 +1,2 @@ - + +
{{selected}}
diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts index 804ab2919c44..0c2f69d21b15 100644 --- a/src/demo-app/date-picker/date-picker-demo.ts +++ b/src/demo-app/date-picker/date-picker-demo.ts @@ -7,4 +7,7 @@ import {Component} from '@angular/core'; templateUrl: 'date-picker-demo.html', styleUrls: ['date-picker-demo.css'] }) -export class DatePickerDemo {} +export class DatePickerDemo { + date = new Date(); + selected = new Date('1/10/2017'); +} diff --git a/src/lib/core/coercion/date-property.ts b/src/lib/core/coercion/date-property.ts new file mode 100644 index 000000000000..a3b1002e0c7a --- /dev/null +++ b/src/lib/core/coercion/date-property.ts @@ -0,0 +1,5 @@ +/** Coerces a data-bound value (typically a string) to a Date. */ +export function coerceDateProperty(value: any, fallbackValue = new Date()): Date { + let timestamp = Date.parse(value); + return isNaN(timestamp) ? fallbackValue : new Date(timestamp); +} diff --git a/src/lib/core/theming/_all-theme.scss b/src/lib/core/theming/_all-theme.scss index 15f21dc21d8f..9e4d6f39d3e2 100644 --- a/src/lib/core/theming/_all-theme.scss +++ b/src/lib/core/theming/_all-theme.scss @@ -6,6 +6,7 @@ @import '../../card/card-theme'; @import '../../checkbox/checkbox-theme'; @import '../../chips/chips-theme'; +@import '../../date-picker/date-picker-theme'; @import '../../dialog/dialog-theme'; @import '../../grid-list/grid-list-theme'; @import '../../icon/icon-theme'; @@ -33,6 +34,7 @@ @include md-card-theme($theme); @include md-checkbox-theme($theme); @include md-chips-theme($theme); + @include md-date-picker-theme($theme); @include md-dialog-theme($theme); @include md-grid-list-theme($theme); @include md-icon-theme($theme); diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/date-picker/_date-picker-theme.scss new file mode 100644 index 000000000000..9fc9de2a0169 --- /dev/null +++ b/src/lib/date-picker/_date-picker-theme.scss @@ -0,0 +1,32 @@ +@import '../core/theming/palette'; +@import '../core/theming/theming'; + + +$md-month-view-today-color: rgba(black, 0.12) !default; + + +@mixin md-date-picker-theme($theme) { + $primary: map-get($theme, primary); + $foreground: map-get($theme, foreground); + + .md-month-view-label { + color: md-color($foreground, secondary-text); + } + + .md-month-view-date { + color: md-color($foreground, text); + + &:hover { + background: md-color($md-grey, 200); + } + + &.md-month-view-selected { + background: md-color($primary); + color: md-color($primary, default-contrast); + } + + &.md-month-view-today { + border-color: $md-month-view-today-color; + } + } +} diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index 57e530675038..8e7ee5a1d837 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -1,8 +1,33 @@ - +
+ + + + + + - + + - - + + + +
{{_monthLabel}}
{{label}} + {{_firstWeekOffset >= 3 ? _monthLabel : ''}} + + {{_getDateString(date)}} +
{{getDateString(date)}}
+ {{_getDateString(date)}} +
diff --git a/src/lib/date-picker/month-view.scss b/src/lib/date-picker/month-view.scss index a3fe87387991..15b8a7b63b56 100644 --- a/src/lib/date-picker/month-view.scss +++ b/src/lib/date-picker/month-view.scss @@ -1,3 +1,33 @@ -md-month-view { - background: red; +$md-month-view-border-spacing: 2px !default; +$md-month-view-font-size: 12px !default; +$md-month-view-date-size: 30px !default; +$md-month-view-date-border-width: 1px !default; + + +.md-month-view-table { + border-spacing: $md-month-view-border-spacing; + font-size: $md-month-view-font-size; +} + +.md-month-view-label { + height: $md-month-view-date-size; + padding: 0 10px; + text-align: left; + font-weight: normal; +} + +.md-month-view-date { + box-sizing: border-box; + width: $md-month-view-date-size; + height: $md-month-view-date-size; + border: $md-month-view-date-border-width solid transparent; + border-radius: 50%; + text-align: center; + vertical-align: middle; +} + +[dir="rtl"] { + .md-month-view-label { + text-align: right; + } } diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index 54b549c90227..a4c2dda1acfb 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -1,4 +1,13 @@ -import {Component, ViewEncapsulation, ChangeDetectionStrategy, Input} from '@angular/core'; +import { + Component, + ViewEncapsulation, + ChangeDetectionStrategy, + Input, + EventEmitter, + Output, + AfterContentInit +} from '@angular/core'; +import {coerceDateProperty} from '../core/coercion/date-property'; @Component({ @@ -9,10 +18,37 @@ import {Component, ViewEncapsulation, ChangeDetectionStrategy, Input} from '@ang encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MdMonthView { - @Input() date: Date = new Date(); +export class MdMonthView implements AfterContentInit { + @Input() + get date() { return this._date; } + set date(value) { + this._date = coerceDateProperty(value); + this._init(); + } + private _date = new Date(); + + @Input() + get selected() { return this._selected; } + set selected(value) { + this._selected = coerceDateProperty(value); + this._selectedDate = (this.selected && this.selected.getMonth() == this.date.getMonth()) ? + this.selected.getDate() : 0; + } + private _selected: Date; + + @Output() selectedChange = new EventEmitter(); + + _monthLabel: string; - localeSettings = { + _weeks: number[][]; + + _firstWeekOffset: number; + + _selectedDate = 0; + + _todayDate = 0; + + private _localeSettings = { firstDayOfWeek: 0, getDateString: (d: number) => '' + d, getMonthLabel: (m: number, y: number) => { @@ -21,39 +57,42 @@ export class MdMonthView { } }; - label: string; - - weeks: number[][]; + ngAfterContentInit(): void { + this._init(); + } - padding: number; + _getDateString(date: number) { + return date === null ? '' : this._localeSettings.getDateString(date); + } - constructor() { - this.label = this.localeSettings.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); - this._calculateWeeks(); + _dateClicked(date: number) { + if (this.selected && this.selected.getDate() == date) { + return; + } + this.selectedChange.emit(new Date(this.date.getFullYear(), this.date.getMonth(), date)); } - private _calculateWeeks() { + private _init() { + this._selectedDate = (this.selected && this.selected.getMonth() == this.date.getMonth()) ? + this.selected.getDate() : 0; + + let today = new Date(); + this._todayDate = (today.getMonth() == this.date.getMonth()) ? today.getDate() : 0; + + this._monthLabel = + this._localeSettings.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); + let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); - let padding = (7 + firstOfMonth.getDay() - this.localeSettings.firstDayOfWeek) % 7; - - // Fill in empty cells at the beginning of the month. - this.weeks = [[]]; - for (let i = 0; i < padding; i++) { - this.weeks[0].push(0); - } + this._firstWeekOffset = (7 + firstOfMonth.getDay() - this._localeSettings.firstDayOfWeek) % 7; - // Fill in the date cells. - for (let i = 0, cell = padding; i < daysInMonth; i++, cell++) { + this._weeks = [[]]; + for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { if (cell == 7) { - this.weeks.push([]); + this._weeks.push([]); cell = 0; } - this.weeks[this.weeks.length - 1].push(i + 1); + this._weeks[this._weeks.length - 1].push(i + 1); } } - - getDateString(date: number) { - return date == 0 ? '' : this.localeSettings.getDateString(date); - } } From 2e78102ac87a572c3fae6ea652f3c2f9e16be936 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Fri, 6 Jan 2017 17:14:36 -0800 Subject: [PATCH 04/19] more month view tweaking --- src/lib/date-picker/_date-picker-theme.scss | 4 ++-- src/lib/date-picker/month-view.html | 22 ++++++++++++--------- src/lib/date-picker/month-view.scss | 11 ++++++++--- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/date-picker/_date-picker-theme.scss index 9fc9de2a0169..7b6f67604318 100644 --- a/src/lib/date-picker/_date-picker-theme.scss +++ b/src/lib/date-picker/_date-picker-theme.scss @@ -16,11 +16,11 @@ $md-month-view-today-color: rgba(black, 0.12) !default; .md-month-view-date { color: md-color($foreground, text); - &:hover { + .md-month-view-date-cell:hover & { background: md-color($md-grey, 200); } - &.md-month-view-selected { + .md-month-view-date-cell &.md-month-view-selected { background: md-color($primary); color: md-color($primary, default-contrast); } diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index 8e7ee5a1d837..b4a7ecd995e5 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -12,22 +12,26 @@ {{_firstWeekOffset >= 3 ? _monthLabel : ''}} - {{_getDateString(date)}} +
+ {{_getDateString(date)}} +
- + - {{_getDateString(date)}} +
+ {{_getDateString(date)}} +
diff --git a/src/lib/date-picker/month-view.scss b/src/lib/date-picker/month-view.scss index 15b8a7b63b56..e5ab482d23d9 100644 --- a/src/lib/date-picker/month-view.scss +++ b/src/lib/date-picker/month-view.scss @@ -1,11 +1,11 @@ -$md-month-view-border-spacing: 2px !default; $md-month-view-font-size: 12px !default; -$md-month-view-date-size: 30px !default; +$md-month-view-date-cell-padding: 1px !default; +$md-month-view-date-size: 32px !default; $md-month-view-date-border-width: 1px !default; .md-month-view-table { - border-spacing: $md-month-view-border-spacing; + border-spacing: 0; font-size: $md-month-view-font-size; } @@ -16,7 +16,12 @@ $md-month-view-date-border-width: 1px !default; font-weight: normal; } +.md-month-view-date-cell { + padding: $md-month-view-date-cell-padding; +} + .md-month-view-date { + display: table-cell; box-sizing: border-box; width: $md-month-view-date-size; height: $md-month-view-date-size; From bcdb462dd21aee49e03a6e9a57b5a5139804683b Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Fri, 6 Jan 2017 17:48:24 -0800 Subject: [PATCH 05/19] started extracting common stuff to calendar-table. --- src/lib/date-picker/calendar-table.html | 37 ++++++++++++++++++ src/lib/date-picker/calendar-table.ts | 51 +++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/lib/date-picker/calendar-table.html create mode 100644 src/lib/date-picker/calendar-table.ts diff --git a/src/lib/date-picker/calendar-table.html b/src/lib/date-picker/calendar-table.html new file mode 100644 index 000000000000..0f5201108f24 --- /dev/null +++ b/src/lib/date-picker/calendar-table.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + +
{{label}}
+ {{_firstRowOffset() >= labelMinCells ? label : ''}} + +
+ {{item.displayValue}} +
+
+
+ {{item.displayName}} +
+
diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/date-picker/calendar-table.ts new file mode 100644 index 000000000000..bdc5f232069d --- /dev/null +++ b/src/lib/date-picker/calendar-table.ts @@ -0,0 +1,51 @@ +import { + Component, + ViewEncapsulation, + ChangeDetectionStrategy, + Input, + EventEmitter, + Output +} from '@angular/core'; + + +const NUM_COLS = 7; + + +export class MdCalendarCell { + constructor(public value: number, public displayValue: string) {} +} + + +@Component({ + moduleId: module.id, + selector: 'md-month-view, mat-month-view', + templateUrl: 'month-view.html', + styleUrls: ['month-view.css'], + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MdCalendarTable { + @Input() label: string; + + @Input() data: MdCalendarCell[][]; + + @Input() todayValue: number; + + @Input() selectedValue: number; + + @Input() labelMinCells: number; + + @Output() selectedValueChange = new EventEmitter(); + + _cellClicked(value: number) { + if (this.selectedValue && this.selectedValue === value) { + return; + } + this.selectedValueChange.emit(value); + } + + _firstRowOffset() { + return this.data && this.data.length && this.data[0].length ? + NUM_COLS - this.data[0].length : 0; + } +} From 102d483efc26c78099d6cce9823d9a3f5b65bcc5 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Sat, 7 Jan 2017 18:21:07 -0800 Subject: [PATCH 06/19] base month view on calendar table --- src/lib/date-picker/_date-picker-theme.scss | 14 +++---- src/lib/date-picker/calendar-table.html | 4 +- src/lib/date-picker/calendar-table.scss | 39 ++++++++++++++++++ src/lib/date-picker/calendar-table.ts | 6 +-- src/lib/date-picker/index.ts | 9 +++-- src/lib/date-picker/month-view.html | 44 ++++----------------- src/lib/date-picker/month-view.ts | 7 ++-- 7 files changed, 68 insertions(+), 55 deletions(-) create mode 100644 src/lib/date-picker/calendar-table.scss diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/date-picker/_date-picker-theme.scss index 7b6f67604318..0f919806d9e1 100644 --- a/src/lib/date-picker/_date-picker-theme.scss +++ b/src/lib/date-picker/_date-picker-theme.scss @@ -2,31 +2,31 @@ @import '../core/theming/theming'; -$md-month-view-today-color: rgba(black, 0.12) !default; +$md-calendar-table-today-color: rgba(black, 0.12) !default; @mixin md-date-picker-theme($theme) { $primary: map-get($theme, primary); $foreground: map-get($theme, foreground); - .md-month-view-label { + .md-calendar-table-label { color: md-color($foreground, secondary-text); } - .md-month-view-date { + .md-calendar-table-cell-content { color: md-color($foreground, text); - .md-month-view-date-cell:hover & { + .md-calendar-table-cell:hover & { background: md-color($md-grey, 200); } - .md-month-view-date-cell &.md-month-view-selected { + .md-calendar-table-cell &.md-calendar-table-selected { background: md-color($primary); color: md-color($primary, default-contrast); } - &.md-month-view-today { - border-color: $md-month-view-today-color; + &.md-calendar-table-today { + border-color: $md-calendar-table-today-color; } } } diff --git a/src/lib/date-picker/calendar-table.html b/src/lib/date-picker/calendar-table.html index 0f5201108f24..be509cdd12b6 100644 --- a/src/lib/date-picker/calendar-table.html +++ b/src/lib/date-picker/calendar-table.html @@ -1,4 +1,4 @@ - +
@@ -30,7 +30,7 @@
- {{item.displayName}} + {{item.displayValue}}
diff --git a/src/lib/date-picker/calendar-table.scss b/src/lib/date-picker/calendar-table.scss new file mode 100644 index 000000000000..3fba6aa12fc7 --- /dev/null +++ b/src/lib/date-picker/calendar-table.scss @@ -0,0 +1,39 @@ +$md-calendar-table-font-size: 12px !default; +$md-calendar-table-cell-padding: 1px !default; +$md-calendar-table-cell-content-size: 32px !default; +$md-calendar-table-cell-content-border-width: 1px !default; + + +.md-calendar-table-table { + border-spacing: 0; + font-size: $md-calendar-table-font-size; +} + +.md-calendar-table-label { + height: $md-calendar-table-cell-content-size; + padding: 0 0 0 10px; + text-align: left; + font-weight: normal; +} + +.md-calendar-table-cell { + padding: $md-calendar-table-cell-padding; +} + +.md-calendar-table-cell-content { + display: table-cell; + box-sizing: border-box; + width: $md-calendar-table-cell-content-size; + height: $md-calendar-table-cell-content-size; + border: $md-calendar-table-cell-content-border-width solid transparent; + border-radius: 50%; + text-align: center; + vertical-align: middle; +} + +[dir="rtl"] { + .md-calendar-table-label { + padding: 0 10px 0 0; + text-align: right; + } +} diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/date-picker/calendar-table.ts index bdc5f232069d..3bcb78cd468f 100644 --- a/src/lib/date-picker/calendar-table.ts +++ b/src/lib/date-picker/calendar-table.ts @@ -18,9 +18,9 @@ export class MdCalendarCell { @Component({ moduleId: module.id, - selector: 'md-month-view, mat-month-view', - templateUrl: 'month-view.html', - styleUrls: ['month-view.css'], + selector: 'md-calendar-table, mat-calendar-table', + templateUrl: 'calendar-table.html', + styleUrls: ['calendar-table.css'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts index afcc8b5d9132..ade28a55861a 100644 --- a/src/lib/date-picker/index.ts +++ b/src/lib/date-picker/index.ts @@ -1,14 +1,17 @@ -import {ModuleWithProviders, NgModule} from '@angular/core'; +import {NgModule, ModuleWithProviders} from '@angular/core'; import {MdMonthView} from './month-view'; import {DefaultStyleCompatibilityModeModule} from '../core/compatibility/default-mode'; import {CommonModule} from '@angular/common'; +import {MdCalendarTable} from './calendar-table'; export * from './month-view'; +export * from './calendar-table'; + @NgModule({ imports: [CommonModule, DefaultStyleCompatibilityModeModule], - exports: [MdMonthView, DefaultStyleCompatibilityModeModule], - declarations: [MdMonthView], + exports: [MdMonthView, MdCalendarTable, DefaultStyleCompatibilityModeModule], + declarations: [MdMonthView, MdCalendarTable], }) export class MdDatePickerModule { static forRoot(): ModuleWithProviders { diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index b4a7ecd995e5..59aecad43e6c 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -1,37 +1,7 @@ -
{{label}}
- - - - - - - - - - - - - - - -
{{_monthLabel}}
- {{_firstWeekOffset >= 3 ? _monthLabel : ''}} - -
- {{_getDateString(date)}} -
-
-
- {{_getDateString(date)}} -
-
+ + \ No newline at end of file diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index a4c2dda1acfb..40ad1b8e1612 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -8,6 +8,7 @@ import { AfterContentInit } from '@angular/core'; import {coerceDateProperty} from '../core/coercion/date-property'; +import {MdCalendarCell} from './calendar-table'; @Component({ @@ -40,7 +41,7 @@ export class MdMonthView implements AfterContentInit { _monthLabel: string; - _weeks: number[][]; + _weeks: MdCalendarCell[][]; _firstWeekOffset: number; @@ -65,7 +66,7 @@ export class MdMonthView implements AfterContentInit { return date === null ? '' : this._localeSettings.getDateString(date); } - _dateClicked(date: number) { + _dateSelected(date: number) { if (this.selected && this.selected.getDate() == date) { return; } @@ -92,7 +93,7 @@ export class MdMonthView implements AfterContentInit { this._weeks.push([]); cell = 0; } - this._weeks[this._weeks.length - 1].push(i + 1); + this._weeks[this._weeks.length - 1].push(new MdCalendarCell(i + 1, this._getDateString(i + 1))); } } } From 1b3ff7b6dfe53ce85ee39689df74d6e021fb54a7 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 10:45:14 -0800 Subject: [PATCH 07/19] added year view --- .../date-picker/date-picker-demo.html | 3 + src/demo-app/date-picker/date-picker-demo.ts | 2 +- src/lib/date-picker/calendar-table.ts | 21 ++++- src/lib/date-picker/date-locale.ts | 35 ++++++++ src/lib/date-picker/index.ts | 14 +++- src/lib/date-picker/month-view.scss | 38 --------- src/lib/date-picker/month-view.ts | 61 +++++++------- src/lib/date-picker/year-view.html | 7 ++ src/lib/date-picker/year-view.ts | 81 +++++++++++++++++++ 9 files changed, 189 insertions(+), 73 deletions(-) create mode 100644 src/lib/date-picker/date-locale.ts delete mode 100644 src/lib/date-picker/month-view.scss create mode 100644 src/lib/date-picker/year-view.html create mode 100644 src/lib/date-picker/year-view.ts diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/date-picker/date-picker-demo.html index 22b931de17e2..e6fce0449920 100644 --- a/src/demo-app/date-picker/date-picker-demo.html +++ b/src/demo-app/date-picker/date-picker-demo.html @@ -1,2 +1,5 @@ + + +
{{selected}}
diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts index 0c2f69d21b15..e96640d4decb 100644 --- a/src/demo-app/date-picker/date-picker-demo.ts +++ b/src/demo-app/date-picker/date-picker-demo.ts @@ -9,5 +9,5 @@ import {Component} from '@angular/core'; }) export class DatePickerDemo { date = new Date(); - selected = new Date('1/10/2017'); + selected: Date; } diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/date-picker/calendar-table.ts index 3bcb78cd468f..cfa6d9a7703c 100644 --- a/src/lib/date-picker/calendar-table.ts +++ b/src/lib/date-picker/calendar-table.ts @@ -8,14 +8,20 @@ import { } from '@angular/core'; -const NUM_COLS = 7; - +/** + * An internal class that represents the data corresponding to a single calendar cell. + * @docs-private + */ export class MdCalendarCell { constructor(public value: number, public displayValue: string) {} } +/** + * An internal component used to display calendar data in a table. + * @docs-private + */ @Component({ moduleId: module.id, selector: 'md-calendar-table, mat-calendar-table', @@ -25,16 +31,25 @@ export class MdCalendarCell { changeDetection: ChangeDetectionStrategy.OnPush, }) export class MdCalendarTable { + /** The label for the table. */ @Input() label: string; + /** The cells to display in the table. */ @Input() data: MdCalendarCell[][]; + /** The value in the table that corresponds to today. */ @Input() todayValue: number; + /** The value in the table that is currently selected. */ @Input() selectedValue: number; + /** The minimum number of free cells needed to fit the label in the first row. */ @Input() labelMinCells: number; + /** The number of columns in the table. */ + @Input() numCols = 7; + + /** Emits when a new value is selected. */ @Output() selectedValueChange = new EventEmitter(); _cellClicked(value: number) { @@ -46,6 +61,6 @@ export class MdCalendarTable { _firstRowOffset() { return this.data && this.data.length && this.data[0].length ? - NUM_COLS - this.data[0].length : 0; + this.numCols - this.data[0].length : 0; } } diff --git a/src/lib/date-picker/date-locale.ts b/src/lib/date-picker/date-locale.ts new file mode 100644 index 000000000000..c07dd2777e81 --- /dev/null +++ b/src/lib/date-picker/date-locale.ts @@ -0,0 +1,35 @@ +/** Date locale info. TODO(mmalerba): Integrate with i18n solution once we know what we're doing. */ +export class DateLocale { + firstDayOfWeek = 0; + + months = [ + { full: 'January', short: 'Jan' }, + { full: 'February', short: 'Feb' }, + { full: 'March', short: 'Mar' }, + { full: 'April', short: 'Apr' }, + { full: 'May', short: 'May' }, + { full: 'June', short: 'Jun' }, + { full: 'July', short: 'Jul' }, + { full: 'August', short: 'Aug' }, + { full: 'September', short: 'Sep' }, + { full: 'October', short: 'Oct' }, + { full: 'November', short: 'Nov' }, + { full: 'December', short: 'Dec' }, + ]; + + days = [ + { full: 'Sunday', short: 'Sun', xshort: 'S' }, + { full: 'Monday', short: 'Mon', xshort: 'M' }, + { full: 'Tuesday', short: 'Tue', xshort: 'T' }, + { full: 'Wednesday', short: 'Wed', xshort: 'W' }, + { full: 'Thursday', short: 'Thu', xshort: 'T' }, + { full: 'Friday', short: 'Fri', xshort: 'F' }, + { full: 'Saturday', short: 'Sat', xshort: 'S' }, + ]; + + getDateLabel(d: number) { return `${d}`; } + + getMonthLabel(m: number, y: number) { return `${this.months[m].short.toUpperCase()} ${y}`; } + + getYearLabel(y: number) { return `${y}`; } +} diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts index ade28a55861a..311e67811744 100644 --- a/src/lib/date-picker/index.ts +++ b/src/lib/date-picker/index.ts @@ -3,21 +3,27 @@ import {MdMonthView} from './month-view'; import {DefaultStyleCompatibilityModeModule} from '../core/compatibility/default-mode'; import {CommonModule} from '@angular/common'; import {MdCalendarTable} from './calendar-table'; +import {DateLocale} from './date-locale'; +import {MdYearView} from './year-view'; + -export * from './month-view'; export * from './calendar-table'; +export * from './date-locale' +export * from './month-view'; +export * from './year-view'; @NgModule({ imports: [CommonModule, DefaultStyleCompatibilityModeModule], - exports: [MdMonthView, MdCalendarTable, DefaultStyleCompatibilityModeModule], - declarations: [MdMonthView, MdCalendarTable], + exports: [MdCalendarTable, MdMonthView, MdYearView, DefaultStyleCompatibilityModeModule], + declarations: [MdCalendarTable, MdMonthView, MdYearView], + providers: [DateLocale] }) export class MdDatePickerModule { static forRoot(): ModuleWithProviders { return { ngModule: MdDatePickerModule, - providers: [] + providers: [DateLocale] }; } } diff --git a/src/lib/date-picker/month-view.scss b/src/lib/date-picker/month-view.scss deleted file mode 100644 index e5ab482d23d9..000000000000 --- a/src/lib/date-picker/month-view.scss +++ /dev/null @@ -1,38 +0,0 @@ -$md-month-view-font-size: 12px !default; -$md-month-view-date-cell-padding: 1px !default; -$md-month-view-date-size: 32px !default; -$md-month-view-date-border-width: 1px !default; - - -.md-month-view-table { - border-spacing: 0; - font-size: $md-month-view-font-size; -} - -.md-month-view-label { - height: $md-month-view-date-size; - padding: 0 10px; - text-align: left; - font-weight: normal; -} - -.md-month-view-date-cell { - padding: $md-month-view-date-cell-padding; -} - -.md-month-view-date { - display: table-cell; - box-sizing: border-box; - width: $md-month-view-date-size; - height: $md-month-view-date-size; - border: $md-month-view-date-border-width solid transparent; - border-radius: 50%; - text-align: center; - vertical-align: middle; -} - -[dir="rtl"] { - .md-month-view-label { - text-align: right; - } -} diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index 40ad1b8e1612..a0acebfe81de 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -9,17 +9,24 @@ import { } from '@angular/core'; import {coerceDateProperty} from '../core/coercion/date-property'; import {MdCalendarCell} from './calendar-table'; +import {DateLocale} from './date-locale'; +/** + * An internal component used to display a single month in the date-picker. + * @docs-private + */ @Component({ moduleId: module.id, selector: 'md-month-view, mat-month-view', templateUrl: 'month-view.html', - styleUrls: ['month-view.css'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) export class MdMonthView implements AfterContentInit { + /** + * The date to display in this month view (everything other than the month and year is ignored). + */ @Input() get date() { return this._date; } set date(value) { @@ -28,44 +35,38 @@ export class MdMonthView implements AfterContentInit { } private _date = new Date(); + /** The currently selected date. */ @Input() get selected() { return this._selected; } set selected(value) { - this._selected = coerceDateProperty(value); - this._selectedDate = (this.selected && this.selected.getMonth() == this.date.getMonth()) ? - this.selected.getDate() : 0; + this._selected = coerceDateProperty(value, null); + this._selectedDate = this._getDateInCurrentMonth(this.selected); } private _selected: Date; + /** Emits when a new date is selected. */ @Output() selectedChange = new EventEmitter(); _monthLabel: string; _weeks: MdCalendarCell[][]; + _daysPerWeek: number; + _firstWeekOffset: number; _selectedDate = 0; _todayDate = 0; - private _localeSettings = { - firstDayOfWeek: 0, - getDateString: (d: number) => '' + d, - getMonthLabel: (m: number, y: number) => { - let months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUL', 'AUG', 'SEP', 'OCT', 'DEC']; - return `${months[m]} ${y}`; - } - }; + constructor(private _locale: DateLocale) { + this._daysPerWeek = _locale.days.length; + } ngAfterContentInit(): void { this._init(); } - _getDateString(date: number) { - return date === null ? '' : this._localeSettings.getDateString(date); - } - _dateSelected(date: number) { if (this.selected && this.selected.getDate() == date) { return; @@ -74,26 +75,32 @@ export class MdMonthView implements AfterContentInit { } private _init() { - this._selectedDate = (this.selected && this.selected.getMonth() == this.date.getMonth()) ? - this.selected.getDate() : 0; - - let today = new Date(); - this._todayDate = (today.getMonth() == this.date.getMonth()) ? today.getDate() : 0; - - this._monthLabel = - this._localeSettings.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); + this._selectedDate = this._getDateInCurrentMonth(this.selected); + this._todayDate = this._getDateInCurrentMonth(new Date()); + this._monthLabel = this._locale.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); - this._firstWeekOffset = (7 + firstOfMonth.getDay() - this._localeSettings.firstDayOfWeek) % 7; + this._firstWeekOffset = + (this._daysPerWeek + firstOfMonth.getDay() - this._locale.firstDayOfWeek) % + this._daysPerWeek; this._weeks = [[]]; for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { - if (cell == 7) { + if (cell == this._daysPerWeek) { this._weeks.push([]); cell = 0; } - this._weeks[this._weeks.length - 1].push(new MdCalendarCell(i + 1, this._getDateString(i + 1))); + this._weeks[this._weeks.length - 1].push( + new MdCalendarCell(i + 1, this._getDateString(i + 1))); } } + + private _getDateString(date: number) { + return date === null ? '' : this._locale.getDateLabel(date); + } + + private _getDateInCurrentMonth(date: Date) { + return date && date.getMonth() == this.date.getMonth() ? date.getDate() : null; + } } diff --git a/src/lib/date-picker/year-view.html b/src/lib/date-picker/year-view.html new file mode 100644 index 000000000000..f62b7da40c1f --- /dev/null +++ b/src/lib/date-picker/year-view.html @@ -0,0 +1,7 @@ + + diff --git a/src/lib/date-picker/year-view.ts b/src/lib/date-picker/year-view.ts new file mode 100644 index 000000000000..b0c7837b26da --- /dev/null +++ b/src/lib/date-picker/year-view.ts @@ -0,0 +1,81 @@ +import { + Component, + ViewEncapsulation, + ChangeDetectionStrategy, + Input, + AfterContentInit, + Output, + EventEmitter +} from '@angular/core'; +import {DateLocale} from './date-locale'; +import {coerceDateProperty} from '../core/coercion/date-property'; +import {MdCalendarCell} from './calendar-table'; + + +/** + * An internal component used to display a single month in the date-picker. + * @docs-private + */ +@Component({ + moduleId: module.id, + selector: 'md-year-view, mat-year-view', + templateUrl: 'year-view.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class MdYearView implements AfterContentInit { + /** The date to display in this year view (everything other than the year is ignored). */ + @Input() + get date() { return this._date; } + set date(value) { + this._date = coerceDateProperty(value); + this._init(); + } + private _date = new Date(); + + /** The currently selected date. */ + @Input() + get selected() { return this._selected; } + set selected(value) { + this._selected = coerceDateProperty(value, null); + this._selectedMonth = this._getMonthInCurrentYear(this.selected); + } + private _selected: Date; + + /** Emits when a new month is selected. */ + @Output() selectedChange = new EventEmitter(); + + _months: MdCalendarCell[][]; + + _yearLabel: string; + + _todayMonth: number; + + _selectedMonth: number; + + constructor(private _locale: DateLocale) { + this._months = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11]].map(row => row.map( + month => new MdCalendarCell(month, this._locale.months[month].short))); + } + + ngAfterContentInit() { + this._init(); + } + + _monthSelected(month: number) { + if (this.selected && this.selected.getMonth() == month) { + return; + } + this.selectedChange.emit(new Date(this.date.getFullYear(), month, 1)); + } + + private _init() { + this._selectedMonth = this._getMonthInCurrentYear(this.selected); + this._todayMonth = this._getMonthInCurrentYear(new Date()); + this._yearLabel = this._locale.getYearLabel(this._date.getFullYear()); + } + + private _getMonthInCurrentYear(date: Date) { + return date && date.getFullYear() == this.date.getFullYear() ? date.getMonth() : null; + } +} From 6f2217c19bef0d83dd61005cfa9506937a8df90c Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 11:03:01 -0800 Subject: [PATCH 08/19] add disclaimers --- src/demo-app/date-picker/date-picker-demo.html | 2 ++ src/lib/date-picker/README.md | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 src/lib/date-picker/README.md diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/date-picker/date-picker-demo.html index e6fce0449920..906b9b848c7f 100644 --- a/src/demo-app/date-picker/date-picker-demo.html +++ b/src/demo-app/date-picker/date-picker-demo.html @@ -1,3 +1,5 @@ +

Work in progress, not ready for use.

+ diff --git a/src/lib/date-picker/README.md b/src/lib/date-picker/README.md new file mode 100644 index 000000000000..abcf6bd5669e --- /dev/null +++ b/src/lib/date-picker/README.md @@ -0,0 +1,3 @@ +# md-date-picker + +Work in progress, not ready for use. From 85f046473a9264a4e4f19f764f81e37f93a7008a Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 15:33:17 -0800 Subject: [PATCH 09/19] addressed comments --- src/lib/date-picker/_date-picker-theme.scss | 8 +++--- src/lib/date-picker/calendar-table.html | 23 ++++------------ src/lib/date-picker/calendar-table.ts | 13 ++++----- src/lib/date-picker/month-view.html | 4 +-- src/lib/date-picker/month-view.ts | 30 ++++++++++++++++----- src/lib/date-picker/year-view.html | 2 +- src/lib/date-picker/year-view.ts | 24 ++++++++++++++--- 7 files changed, 62 insertions(+), 42 deletions(-) diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/date-picker/_date-picker-theme.scss index 0f919806d9e1..cc88bc96ec9d 100644 --- a/src/lib/date-picker/_date-picker-theme.scss +++ b/src/lib/date-picker/_date-picker-theme.scss @@ -2,12 +2,10 @@ @import '../core/theming/theming'; -$md-calendar-table-today-color: rgba(black, 0.12) !default; - - @mixin md-date-picker-theme($theme) { $primary: map-get($theme, primary); $foreground: map-get($theme, foreground); + $background: map-get($theme, background); .md-calendar-table-label { color: md-color($foreground, secondary-text); @@ -17,7 +15,7 @@ $md-calendar-table-today-color: rgba(black, 0.12) !default; color: md-color($foreground, text); .md-calendar-table-cell:hover & { - background: md-color($md-grey, 200); + background: md-color($background, hover); } .md-calendar-table-cell &.md-calendar-table-selected { @@ -26,7 +24,7 @@ $md-calendar-table-today-color: rgba(black, 0.12) !default; } &.md-calendar-table-today { - border-color: $md-calendar-table-today-color; + border-color: md-color($foreground, divider); } } } diff --git a/src/lib/date-picker/calendar-table.html b/src/lib/date-picker/calendar-table.html index be509cdd12b6..b59c5a12f15a 100644 --- a/src/lib/date-picker/calendar-table.html +++ b/src/lib/date-picker/calendar-table.html @@ -1,15 +1,15 @@ - + - - - - - - -
{{label}}
+ - {{_firstRowOffset() >= labelMinCells ? label : ''}} + [attr.colspan]="_firstRowOffset"> + {{_firstRowOffset >= labelMinCells ? label : ''}}
-
- {{item.displayValue}} -
-
diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/date-picker/calendar-table.ts index cfa6d9a7703c..0e809e0c9585 100644 --- a/src/lib/date-picker/calendar-table.ts +++ b/src/lib/date-picker/calendar-table.ts @@ -24,18 +24,18 @@ export class MdCalendarCell { */ @Component({ moduleId: module.id, - selector: 'md-calendar-table, mat-calendar-table', + selector: 'md-calendar-table', templateUrl: 'calendar-table.html', styleUrls: ['calendar-table.css'], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) export class MdCalendarTable { - /** The label for the table. */ + /** The label for the table. (e.g. "Jan 2017"). */ @Input() label: string; /** The cells to display in the table. */ - @Input() data: MdCalendarCell[][]; + @Input() rows: MdCalendarCell[][]; /** The value in the table that corresponds to today. */ @Input() todayValue: number; @@ -59,8 +59,9 @@ export class MdCalendarTable { this.selectedValueChange.emit(value); } - _firstRowOffset() { - return this.data && this.data.length && this.data[0].length ? - this.numCols - this.data[0].length : 0; + /** The number of blank cells to put at the beginning for the first row. */ + get _firstRowOffset() { + return this.rows && this.rows.length && this.rows[0].length ? + this.numCols - this.rows[0].length : 0; } } diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index 59aecad43e6c..9476ae96585a 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -1,7 +1,7 @@ - \ No newline at end of file + diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index a0acebfe81de..cfd287dded20 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -18,7 +18,7 @@ import {DateLocale} from './date-locale'; */ @Component({ moduleId: module.id, - selector: 'md-month-view, mat-month-view', + selector: 'md-month-view', templateUrl: 'month-view.html', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, @@ -47,16 +47,25 @@ export class MdMonthView implements AfterContentInit { /** Emits when a new date is selected. */ @Output() selectedChange = new EventEmitter(); + /** The label for this month (e.g. "January 2017"). */ _monthLabel: string; + /** Grid of calendar cells representing the dates of the month. */ _weeks: MdCalendarCell[][]; + /** The number of days in a week. */ _daysPerWeek: number; + /** The number of blank cells in the first row before the 1st of the month. */ _firstWeekOffset: number; + /** + * The date of the month that the currently selected Date falls on. + * Null if the currently selected Date is in another month. + */ _selectedDate = 0; + /** The date of the month that today falls on. Null if today is in another month. */ _todayDate = 0; constructor(private _locale: DateLocale) { @@ -67,6 +76,7 @@ export class MdMonthView implements AfterContentInit { this._init(); } + /** Handles when a new date is selected. */ _dateSelected(date: number) { if (this.selected && this.selected.getDate() == date) { return; @@ -74,17 +84,23 @@ export class MdMonthView implements AfterContentInit { this.selectedChange.emit(new Date(this.date.getFullYear(), this.date.getMonth(), date)); } + /** Initializes this month view. */ private _init() { this._selectedDate = this._getDateInCurrentMonth(this.selected); this._todayDate = this._getDateInCurrentMonth(new Date()); this._monthLabel = this._locale.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); - let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); this._firstWeekOffset = (this._daysPerWeek + firstOfMonth.getDay() - this._locale.firstDayOfWeek) % this._daysPerWeek; + this._createWeekCells(); + } + + /** Creates MdCalendarCells for the dates in this month. */ + private _createWeekCells() { + let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); this._weeks = [[]]; for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { if (cell == this._daysPerWeek) { @@ -92,14 +108,14 @@ export class MdMonthView implements AfterContentInit { cell = 0; } this._weeks[this._weeks.length - 1].push( - new MdCalendarCell(i + 1, this._getDateString(i + 1))); + new MdCalendarCell(i + 1, this._locale.getDateLabel(i + 1))); } } - private _getDateString(date: number) { - return date === null ? '' : this._locale.getDateLabel(date); - } - + /** + * Gets the date in this month that the given Date falls on. + * Returns null if the given Date is in another year. + */ private _getDateInCurrentMonth(date: Date) { return date && date.getMonth() == this.date.getMonth() ? date.getDate() : null; } diff --git a/src/lib/date-picker/year-view.html b/src/lib/date-picker/year-view.html index f62b7da40c1f..0b0fbd987442 100644 --- a/src/lib/date-picker/year-view.html +++ b/src/lib/date-picker/year-view.html @@ -1,5 +1,5 @@ (); + /** Grid of calendar cells representing the months of the year. */ _months: MdCalendarCell[][]; + /** The label for this year (e.g. "2017"). */ _yearLabel: string; + /** The month in this year that today falls on. Null if today is in a different year. */ _todayMonth: number; + /** + * The month in this year that the selected Date falls on. + * Null if the selected Date is in a different year. + */ _selectedMonth: number; constructor(private _locale: DateLocale) { this._months = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11]].map(row => row.map( - month => new MdCalendarCell(month, this._locale.months[month].short))); + month => this._createCellForMonth(month))); } ngAfterContentInit() { this._init(); } + /** Handles when a new month is selected. */ _monthSelected(month: number) { if (this.selected && this.selected.getMonth() == month) { return; @@ -69,13 +77,23 @@ export class MdYearView implements AfterContentInit { this.selectedChange.emit(new Date(this.date.getFullYear(), month, 1)); } + /** Initializes this month view. */ private _init() { this._selectedMonth = this._getMonthInCurrentYear(this.selected); this._todayMonth = this._getMonthInCurrentYear(new Date()); this._yearLabel = this._locale.getYearLabel(this._date.getFullYear()); } + /** + * Gets the month in this year that the given Date falls on. + * Returns null if the given Date is in another year. + */ private _getMonthInCurrentYear(date: Date) { return date && date.getFullYear() == this.date.getFullYear() ? date.getMonth() : null; } + + /** Creates an MdCalendarCell for the given month. */ + private _createCellForMonth(month: number) { + return new MdCalendarCell(month, this._locale.months[month].short); + } } From 35b8a9d73d792fd21035f1a80b6e752e0a7048e1 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 15:35:25 -0800 Subject: [PATCH 10/19] fix lint --- src/lib/date-picker/calendar-table.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/date-picker/calendar-table.scss b/src/lib/date-picker/calendar-table.scss index 3fba6aa12fc7..db79c8e3e0f1 100644 --- a/src/lib/date-picker/calendar-table.scss +++ b/src/lib/date-picker/calendar-table.scss @@ -31,7 +31,7 @@ $md-calendar-table-cell-content-border-width: 1px !default; vertical-align: middle; } -[dir="rtl"] { +[dir='rtl'] { .md-calendar-table-label { padding: 0 10px 0 0; text-align: right; From 1aabacca78879ec067b519f8b97c1c2a46a7eb28 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 15:45:06 -0800 Subject: [PATCH 11/19] fixed aot and added comment --- src/demo-app/date-picker/date-picker-demo.ts | 3 +-- src/lib/date-picker/year-view.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts index e96640d4decb..c26af85cc981 100644 --- a/src/demo-app/date-picker/date-picker-demo.ts +++ b/src/demo-app/date-picker/date-picker-demo.ts @@ -4,8 +4,7 @@ import {Component} from '@angular/core'; @Component({ moduleId: module.id, selector: 'date-picker-demo', - templateUrl: 'date-picker-demo.html', - styleUrls: ['date-picker-demo.css'] + templateUrl: 'date-picker-demo.html' }) export class DatePickerDemo { date = new Date(); diff --git a/src/lib/date-picker/year-view.ts b/src/lib/date-picker/year-view.ts index 7eea04bd4fab..da0363ac30da 100644 --- a/src/lib/date-picker/year-view.ts +++ b/src/lib/date-picker/year-view.ts @@ -61,6 +61,7 @@ export class MdYearView implements AfterContentInit { _selectedMonth: number; constructor(private _locale: DateLocale) { + // First row of months only contains 5 elements so we can fit the year label on the same row. this._months = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11]].map(row => row.map( month => this._createCellForMonth(month))); } From 81f587ad1f1a246ddeaff5d18503d52b18270ed4 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Mon, 9 Jan 2017 17:09:58 -0800 Subject: [PATCH 12/19] started on tests --- src/lib/date-picker/calendar-table.html | 6 +- src/lib/date-picker/calendar-table.spec.ts | 86 ++++++++++++++++++++++ src/lib/date-picker/calendar-table.ts | 2 +- src/lib/date-picker/month-view.html | 2 +- src/lib/date-picker/month-view.ts | 15 ++-- src/lib/date-picker/year-view.html | 2 +- 6 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 src/lib/date-picker/calendar-table.spec.ts diff --git a/src/lib/date-picker/calendar-table.html b/src/lib/date-picker/calendar-table.html index b59c5a12f15a..830d93aa8471 100644 --- a/src/lib/date-picker/calendar-table.html +++ b/src/lib/date-picker/calendar-table.html @@ -1,7 +1,7 @@ - - + + @@ -9,7 +9,7 @@
{{label}}
{{label}}
- {{_firstRowOffset >= labelMinCells ? label : ''}} + {{_firstRowOffset >= labelMinRequiredCells ? label : ''}} { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MdDatePickerModule], + declarations: [ + StandardCalendarTable, + ], + }); + + TestBed.compileComponents(); + })); + + describe('standard calendar table', () => { + let fixture: ComponentFixture; + let calendarTableInstance: StandardCalendarTable; + let calendarTableNativeElement: Element; + let rowEls: NodeListOf; + let labelEls: NodeListOf; + let cellEls: NodeListOf; + + let refreshElementLists = () => { + rowEls = calendarTableNativeElement.querySelectorAll('tr'); + labelEls = calendarTableNativeElement.querySelectorAll('.md-calendar-table-label'); + cellEls = calendarTableNativeElement.querySelectorAll('.md-calendar-table-cell'); + }; + + beforeEach(() => { + fixture = TestBed.createComponent(StandardCalendarTable); + fixture.detectChanges(); + + let calendarTableDebugElement = fixture.debugElement.query(By.directive(MdCalendarTable)); + calendarTableNativeElement = calendarTableDebugElement.nativeElement; + calendarTableInstance = calendarTableDebugElement.componentInstance; + + refreshElementLists(); + }); + + it('creates table', () => { + expect(rowEls.length).toBe(3); + expect(labelEls.length).toBe(1); + expect(cellEls.length).toBe(14); + }); + + it('highlights today', () => { + let todayCell = calendarTableNativeElement.querySelector('.md-calendar-table-today'); + expect(todayCell).not.toBeNull(); + expect(todayCell.innerHTML).toBe('3'); + }) + }); +}); + + +@Component({ + template: ` + `, +}) +class StandardCalendarTable { + label = 'Jan 2017'; + rows = [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]].map(r => r.map(c => createCell)); + todayValue = 3; + selectedValue = 4; + labelMinRequiredCells = 3; + numCols = 7; + + onSelect(value: number) { + this.selectedValue = value; + } +} + + +function createCell(value: number) { + return new MdCalendarCell(value, `${value}`); +} diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/date-picker/calendar-table.ts index 0e809e0c9585..2df28f6b4378 100644 --- a/src/lib/date-picker/calendar-table.ts +++ b/src/lib/date-picker/calendar-table.ts @@ -44,7 +44,7 @@ export class MdCalendarTable { @Input() selectedValue: number; /** The minimum number of free cells needed to fit the label in the first row. */ - @Input() labelMinCells: number; + @Input() labelMinRequiredCells: number; /** The number of columns in the table. */ @Input() numCols = 7; diff --git a/src/lib/date-picker/month-view.html b/src/lib/date-picker/month-view.html index 9476ae96585a..e0e0559cfc9c 100644 --- a/src/lib/date-picker/month-view.html +++ b/src/lib/date-picker/month-view.html @@ -2,6 +2,6 @@ [rows]="_weeks" [todayValue]="_todayDate" [selectedValue]="_selectedDate" - [labelMinCells]="3" + [labelMinRequiredCells]="3" (selectedValueChange)="_dateSelected($event)"> diff --git a/src/lib/date-picker/month-view.ts b/src/lib/date-picker/month-view.ts index cfd287dded20..2a6be9f08220 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/date-picker/month-view.ts @@ -12,6 +12,9 @@ import {MdCalendarCell} from './calendar-table'; import {DateLocale} from './date-locale'; +const DAYS_PER_WEEK = 7; + + /** * An internal component used to display a single month in the date-picker. * @docs-private @@ -53,9 +56,6 @@ export class MdMonthView implements AfterContentInit { /** Grid of calendar cells representing the dates of the month. */ _weeks: MdCalendarCell[][]; - /** The number of days in a week. */ - _daysPerWeek: number; - /** The number of blank cells in the first row before the 1st of the month. */ _firstWeekOffset: number; @@ -68,9 +68,7 @@ export class MdMonthView implements AfterContentInit { /** The date of the month that today falls on. Null if today is in another month. */ _todayDate = 0; - constructor(private _locale: DateLocale) { - this._daysPerWeek = _locale.days.length; - } + constructor(private _locale: DateLocale) {} ngAfterContentInit(): void { this._init(); @@ -92,8 +90,7 @@ export class MdMonthView implements AfterContentInit { let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); this._firstWeekOffset = - (this._daysPerWeek + firstOfMonth.getDay() - this._locale.firstDayOfWeek) % - this._daysPerWeek; + (DAYS_PER_WEEK + firstOfMonth.getDay() - this._locale.firstDayOfWeek) % DAYS_PER_WEEK; this._createWeekCells(); } @@ -103,7 +100,7 @@ export class MdMonthView implements AfterContentInit { let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); this._weeks = [[]]; for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { - if (cell == this._daysPerWeek) { + if (cell == DAYS_PER_WEEK) { this._weeks.push([]); cell = 0; } diff --git a/src/lib/date-picker/year-view.html b/src/lib/date-picker/year-view.html index 0b0fbd987442..c2aa74d8e08c 100644 --- a/src/lib/date-picker/year-view.html +++ b/src/lib/date-picker/year-view.html @@ -2,6 +2,6 @@ [rows]="_months" [todayValue]="_todayMonth" [selectedValue]="_selectedMonth" - [labelMinCells]="2" + [labelMinRequiredCells]="2" (selectedValueChange)="_monthSelected($event)"> From 7b5e4ba89ad795b4049b288112d17a47a79cd6ee Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 10 Jan 2017 10:22:24 -0800 Subject: [PATCH 13/19] calendar table tests --- src/lib/date-picker/calendar-table.spec.ts | 40 +++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/lib/date-picker/calendar-table.spec.ts b/src/lib/date-picker/calendar-table.spec.ts index 65f0c3fcfdff..7a143691124a 100644 --- a/src/lib/date-picker/calendar-table.spec.ts +++ b/src/lib/date-picker/calendar-table.spec.ts @@ -1,6 +1,6 @@ import {async, TestBed, ComponentFixture} from '@angular/core/testing'; import {MdDatePickerModule} from './index'; -import {Component, DebugElement} from '@angular/core'; +import {Component} from '@angular/core'; import {MdCalendarTable, MdCalendarCell} from './calendar-table'; import {By} from '@angular/platform-browser'; @@ -37,7 +37,7 @@ describe('MdCalendarTable', () => { let calendarTableDebugElement = fixture.debugElement.query(By.directive(MdCalendarTable)); calendarTableNativeElement = calendarTableDebugElement.nativeElement; - calendarTableInstance = calendarTableDebugElement.componentInstance; + calendarTableInstance = fixture.componentInstance; refreshElementLists(); }); @@ -51,8 +51,38 @@ describe('MdCalendarTable', () => { it('highlights today', () => { let todayCell = calendarTableNativeElement.querySelector('.md-calendar-table-today'); expect(todayCell).not.toBeNull(); - expect(todayCell.innerHTML).toBe('3'); - }) + expect(todayCell.innerHTML.trim()).toBe('3'); + }); + + it('highlights selected', () => { + let todayCell = calendarTableNativeElement.querySelector('.md-calendar-table-selected'); + expect(todayCell).not.toBeNull(); + expect(todayCell.innerHTML.trim()).toBe('4'); + }); + + it('places label in first row if space is available', () => { + calendarTableInstance.rows[0] = calendarTableInstance.rows[0].slice(3); + calendarTableInstance.rows = calendarTableInstance.rows.slice(); + fixture.detectChanges(); + refreshElementLists(); + + expect(rowEls.length).toBe(2); + expect(labelEls.length).toBe(1); + expect(cellEls.length).toBe(11); + expect(rowEls[0].firstElementChild.classList.contains('md-calendar-table-label')).toBe( + true, 'first cell should be the label'); + expect(labelEls[0].getAttribute('colspan')).toBe('3'); + }); + + it('cell should be selected on click', () => { + let todayElement = + calendarTableNativeElement.querySelector('.md-calendar-table-today') as HTMLElement; + todayElement.click(); + fixture.detectChanges(); + + expect(todayElement.classList.contains('md-calendar-table-selected')).toBe( + true, 'today should be selected'); + }); }); }); @@ -69,7 +99,7 @@ describe('MdCalendarTable', () => { }) class StandardCalendarTable { label = 'Jan 2017'; - rows = [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]].map(r => r.map(c => createCell)); + rows = [[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]].map(r => r.map(createCell)); todayValue = 3; selectedValue = 4; labelMinRequiredCells = 3; From 52cee53fa550efb1e260c8b35186592a273129f4 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Tue, 10 Jan 2017 11:23:02 -0800 Subject: [PATCH 14/19] tests for month and year view --- src/lib/date-picker/calendar-table.spec.ts | 8 +-- src/lib/date-picker/month-view.spec.ts | 78 ++++++++++++++++++++++ src/lib/date-picker/year-view.spec.ts | 78 ++++++++++++++++++++++ 3 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 src/lib/date-picker/month-view.spec.ts create mode 100644 src/lib/date-picker/year-view.spec.ts diff --git a/src/lib/date-picker/calendar-table.spec.ts b/src/lib/date-picker/calendar-table.spec.ts index 7a143691124a..ef4fc7dcab67 100644 --- a/src/lib/date-picker/calendar-table.spec.ts +++ b/src/lib/date-picker/calendar-table.spec.ts @@ -19,7 +19,7 @@ describe('MdCalendarTable', () => { describe('standard calendar table', () => { let fixture: ComponentFixture; - let calendarTableInstance: StandardCalendarTable; + let testComponent: StandardCalendarTable; let calendarTableNativeElement: Element; let rowEls: NodeListOf; let labelEls: NodeListOf; @@ -37,7 +37,7 @@ describe('MdCalendarTable', () => { let calendarTableDebugElement = fixture.debugElement.query(By.directive(MdCalendarTable)); calendarTableNativeElement = calendarTableDebugElement.nativeElement; - calendarTableInstance = fixture.componentInstance; + testComponent = fixture.componentInstance; refreshElementLists(); }); @@ -61,8 +61,8 @@ describe('MdCalendarTable', () => { }); it('places label in first row if space is available', () => { - calendarTableInstance.rows[0] = calendarTableInstance.rows[0].slice(3); - calendarTableInstance.rows = calendarTableInstance.rows.slice(); + testComponent.rows[0] = testComponent.rows[0].slice(3); + testComponent.rows = testComponent.rows.slice(); fixture.detectChanges(); refreshElementLists(); diff --git a/src/lib/date-picker/month-view.spec.ts b/src/lib/date-picker/month-view.spec.ts new file mode 100644 index 000000000000..161cc6eee8fc --- /dev/null +++ b/src/lib/date-picker/month-view.spec.ts @@ -0,0 +1,78 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MdDatePickerModule} from './index'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; +import {MdMonthView} from './month-view'; + + +describe('MdMonthView', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MdDatePickerModule], + declarations: [ + StandardMonthView, + ], + }); + + TestBed.compileComponents(); + })); + + describe('standard year view', () => { + let fixture: ComponentFixture; + let testComponent: StandardMonthView; + let monthViewNativeElement: Element; + + beforeEach(() => { + fixture = TestBed.createComponent(StandardMonthView); + fixture.detectChanges(); + + let monthViewDebugElement = fixture.debugElement.query(By.directive(MdMonthView)); + monthViewNativeElement = monthViewDebugElement.nativeElement; + testComponent = fixture.componentInstance; + }); + + it('has correct year label', () => { + let labelEl = monthViewNativeElement.querySelector('.md-calendar-table-label'); + expect(labelEl.innerHTML.trim()).toBe('JAN 2017'); + }); + + it('has 31 days', () => { + let cellEls = monthViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + expect(cellEls.length).toBe(31); + }); + + it('shows selected date if in same month', () => { + let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl.innerHTML.trim()).toBe('10'); + }); + + it('does not show selected date if in different month', () => { + testComponent.selected = new Date('3/10/2017'); + fixture.detectChanges(); + + let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl).toBeNull(); + }); + + it('fires selected change event on cell clicked', () => { + let cellEls = monthViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + (cellEls[cellEls.length - 1] as HTMLElement).click(); + fixture.detectChanges(); + + let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl.innerHTML.trim()).toBe('31'); + }); + }); +}); + + +@Component({ + template: ` + `, +}) +class StandardMonthView { + date = new Date('1/5/2017'); + selected = new Date('1/10/2017'); +} diff --git a/src/lib/date-picker/year-view.spec.ts b/src/lib/date-picker/year-view.spec.ts new file mode 100644 index 000000000000..736d9442b5fb --- /dev/null +++ b/src/lib/date-picker/year-view.spec.ts @@ -0,0 +1,78 @@ +import {async, TestBed, ComponentFixture} from '@angular/core/testing'; +import {MdDatePickerModule} from './index'; +import {Component} from '@angular/core'; +import {By} from '@angular/platform-browser'; +import {MdYearView} from './year-view'; + + +describe('MdYearView', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MdDatePickerModule], + declarations: [ + StandardYearView, + ], + }); + + TestBed.compileComponents(); + })); + + describe('standard year view', () => { + let fixture: ComponentFixture; + let testComponent: StandardYearView; + let yearViewNativeElement: Element; + + beforeEach(() => { + fixture = TestBed.createComponent(StandardYearView); + fixture.detectChanges(); + + let yearViewDebugElement = fixture.debugElement.query(By.directive(MdYearView)); + yearViewNativeElement = yearViewDebugElement.nativeElement; + testComponent = fixture.componentInstance; + }); + + it('has correct year label', () => { + let labelEl = yearViewNativeElement.querySelector('.md-calendar-table-label'); + expect(labelEl.innerHTML.trim()).toBe('2017'); + }); + + it('has 12 months', () => { + let cellEls = yearViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + expect(cellEls.length).toBe(12); + }); + + it('shows selected month if in same year', () => { + let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl.innerHTML.trim()).toBe('Mar'); + }); + + it('does not show selected month if in different year', () => { + testComponent.selected = new Date('3/10/2016'); + fixture.detectChanges(); + + let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl).toBeNull(); + }); + + it('fires selected change event on cell clicked', () => { + let cellEls = yearViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + (cellEls[cellEls.length - 1] as HTMLElement).click(); + fixture.detectChanges(); + + let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + expect(selectedEl.innerHTML.trim()).toBe('Dec'); + }); + }); +}); + + +@Component({ + template: ` + `, +}) +class StandardYearView { + date = new Date('1/5/2017'); + selected = new Date('3/10/2017'); +} From 07b3080ff4c2eedd3e52c1940369b0aa6245c6eb Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 1 Feb 2017 15:58:28 -0800 Subject: [PATCH 15/19] rebase on top of CalendarLocale & SimpleDate --- src/demo-app/date-picker/date-picker-demo.ts | 12 ------ .../datepicker-demo.html} | 2 +- src/demo-app/datepicker/datepicker-demo.ts | 13 ++++++ src/demo-app/demo-app-module.ts | 4 +- src/demo-app/demo-app/demo-app.ts | 2 +- src/demo-app/demo-app/routes.ts | 4 +- src/lib/core/coercion/date-property.ts | 5 --- src/lib/core/theming/_all-theme.scss | 4 +- src/lib/date-picker/calendar-table.scss | 39 ----------------- src/lib/date-picker/date-locale.ts | 35 ---------------- src/lib/date-picker/index.ts | 29 ------------- src/lib/{date-picker => datepicker}/README.md | 2 +- .../_datepicker-theme.scss} | 12 +++--- .../calendar-table.html | 14 +++---- src/lib/datepicker/calendar-table.scss | 39 +++++++++++++++++ .../calendar-table.spec.ts | 18 ++++---- .../calendar-table.ts | 1 - src/lib/datepicker/index.ts | 19 +++++++++ .../month-view.html | 0 .../month-view.spec.ts | 30 +++++++------ .../{date-picker => datepicker}/month-view.ts | 42 ++++++++++--------- .../year-view.html | 0 .../year-view.spec.ts | 28 ++++++------- .../{date-picker => datepicker}/year-view.ts | 32 +++++++------- src/lib/index.ts | 2 +- src/lib/module.ts | 5 +-- 26 files changed, 170 insertions(+), 223 deletions(-) delete mode 100644 src/demo-app/date-picker/date-picker-demo.ts rename src/demo-app/{date-picker/date-picker-demo.html => datepicker/datepicker-demo.html} (82%) create mode 100644 src/demo-app/datepicker/datepicker-demo.ts delete mode 100644 src/lib/core/coercion/date-property.ts delete mode 100644 src/lib/date-picker/calendar-table.scss delete mode 100644 src/lib/date-picker/date-locale.ts delete mode 100644 src/lib/date-picker/index.ts rename src/lib/{date-picker => datepicker}/README.md (69%) rename src/lib/{date-picker/_date-picker-theme.scss => datepicker/_datepicker-theme.scss} (68%) rename src/lib/{date-picker => datepicker}/calendar-table.html (59%) create mode 100644 src/lib/datepicker/calendar-table.scss rename src/lib/{date-picker => datepicker}/calendar-table.spec.ts (86%) rename src/lib/{date-picker => datepicker}/calendar-table.ts (99%) create mode 100644 src/lib/datepicker/index.ts rename src/lib/{date-picker => datepicker}/month-view.html (100%) rename src/lib/{date-picker => datepicker}/month-view.spec.ts (61%) rename src/lib/{date-picker => datepicker}/month-view.ts (64%) rename src/lib/{date-picker => datepicker}/year-view.html (100%) rename src/lib/{date-picker => datepicker}/year-view.spec.ts (63%) rename src/lib/{date-picker => datepicker}/year-view.ts (69%) diff --git a/src/demo-app/date-picker/date-picker-demo.ts b/src/demo-app/date-picker/date-picker-demo.ts deleted file mode 100644 index c26af85cc981..000000000000 --- a/src/demo-app/date-picker/date-picker-demo.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Component} from '@angular/core'; - - -@Component({ - moduleId: module.id, - selector: 'date-picker-demo', - templateUrl: 'date-picker-demo.html' -}) -export class DatePickerDemo { - date = new Date(); - selected: Date; -} diff --git a/src/demo-app/date-picker/date-picker-demo.html b/src/demo-app/datepicker/datepicker-demo.html similarity index 82% rename from src/demo-app/date-picker/date-picker-demo.html rename to src/demo-app/datepicker/datepicker-demo.html index 906b9b848c7f..65903b322f5b 100644 --- a/src/demo-app/date-picker/date-picker-demo.html +++ b/src/demo-app/datepicker/datepicker-demo.html @@ -4,4 +4,4 @@

Work in progress, not ready for use.


-
{{selected}}
+
{{selected?.toNativeDate()}}
diff --git a/src/demo-app/datepicker/datepicker-demo.ts b/src/demo-app/datepicker/datepicker-demo.ts new file mode 100644 index 000000000000..f0d32f6bb24a --- /dev/null +++ b/src/demo-app/datepicker/datepicker-demo.ts @@ -0,0 +1,13 @@ +import {Component} from '@angular/core'; +import {SimpleDate} from '@angular/material'; + + +@Component({ + moduleId: module.id, + selector: 'datepicker-demo', + templateUrl: 'datepicker-demo.html' +}) +export class DatepickerDemo { + date = SimpleDate.fromNativeDate(new Date()); + selected: SimpleDate; +} diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts index 786bd1aaa4fe..df64c5326ef4 100644 --- a/src/demo-app/demo-app-module.ts +++ b/src/demo-app/demo-app-module.ts @@ -38,7 +38,7 @@ import {ProjectionDemo, ProjectionTestComponent} from './projection/projection-d import {PlatformDemo} from './platform/platform-demo'; import {AutocompleteDemo} from './autocomplete/autocomplete-demo'; import {InputContainerDemo} from './input/input-container-demo'; -import {DatePickerDemo} from './date-picker/date-picker-demo'; +import {DatepickerDemo} from './datepicker/datepicker-demo'; @NgModule({ imports: [ @@ -57,7 +57,7 @@ import {DatePickerDemo} from './date-picker/date-picker-demo'; CardDemo, ChipsDemo, CheckboxDemo, - DatePickerDemo, + DatepickerDemo, DemoApp, DialogDemo, GesturesDemo, diff --git a/src/demo-app/demo-app/demo-app.ts b/src/demo-app/demo-app/demo-app.ts index 3111c9515bfd..4338bf5f175d 100644 --- a/src/demo-app/demo-app/demo-app.ts +++ b/src/demo-app/demo-app/demo-app.ts @@ -26,7 +26,7 @@ export class DemoApp { {name: 'Card', route: 'card'}, {name: 'Chips', route: 'chips'}, {name: 'Checkbox', route: 'checkbox'}, - {name: 'Date Picker', route: 'date-picker'}, + {name: 'Datepicker', route: 'datepicker'}, {name: 'Dialog', route: 'dialog'}, {name: 'Gestures', route: 'gestures'}, {name: 'Grid List', route: 'grid-list'}, diff --git a/src/demo-app/demo-app/routes.ts b/src/demo-app/demo-app/routes.ts index 7319643021f8..f62fb2faafb6 100644 --- a/src/demo-app/demo-app/routes.ts +++ b/src/demo-app/demo-app/routes.ts @@ -32,7 +32,7 @@ import {TABS_DEMO_ROUTES} from '../tabs/routes'; import {PlatformDemo} from '../platform/platform-demo'; import {AutocompleteDemo} from '../autocomplete/autocomplete-demo'; import {InputContainerDemo} from '../input/input-container-demo'; -import {DatePickerDemo} from '../date-picker/date-picker-demo'; +import {DatepickerDemo} from '../datepicker/datepicker-demo'; export const DEMO_APP_ROUTES: Routes = [ {path: '', component: Home}, @@ -40,7 +40,7 @@ export const DEMO_APP_ROUTES: Routes = [ {path: 'button', component: ButtonDemo}, {path: 'card', component: CardDemo}, {path: 'chips', component: ChipsDemo}, - {path: 'date-picker', component: DatePickerDemo}, + {path: 'datepicker', component: DatepickerDemo}, {path: 'radio', component: RadioDemo}, {path: 'select', component: SelectDemo}, {path: 'sidenav', component: SidenavDemo}, diff --git a/src/lib/core/coercion/date-property.ts b/src/lib/core/coercion/date-property.ts deleted file mode 100644 index a3b1002e0c7a..000000000000 --- a/src/lib/core/coercion/date-property.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** Coerces a data-bound value (typically a string) to a Date. */ -export function coerceDateProperty(value: any, fallbackValue = new Date()): Date { - let timestamp = Date.parse(value); - return isNaN(timestamp) ? fallbackValue : new Date(timestamp); -} diff --git a/src/lib/core/theming/_all-theme.scss b/src/lib/core/theming/_all-theme.scss index 9e4d6f39d3e2..bd252577070e 100644 --- a/src/lib/core/theming/_all-theme.scss +++ b/src/lib/core/theming/_all-theme.scss @@ -6,7 +6,7 @@ @import '../../card/card-theme'; @import '../../checkbox/checkbox-theme'; @import '../../chips/chips-theme'; -@import '../../date-picker/date-picker-theme'; +@import '../../datepicker/datepicker-theme'; @import '../../dialog/dialog-theme'; @import '../../grid-list/grid-list-theme'; @import '../../icon/icon-theme'; @@ -34,7 +34,7 @@ @include md-card-theme($theme); @include md-checkbox-theme($theme); @include md-chips-theme($theme); - @include md-date-picker-theme($theme); + @include mat-datepicker-theme($theme); @include md-dialog-theme($theme); @include md-grid-list-theme($theme); @include md-icon-theme($theme); diff --git a/src/lib/date-picker/calendar-table.scss b/src/lib/date-picker/calendar-table.scss deleted file mode 100644 index db79c8e3e0f1..000000000000 --- a/src/lib/date-picker/calendar-table.scss +++ /dev/null @@ -1,39 +0,0 @@ -$md-calendar-table-font-size: 12px !default; -$md-calendar-table-cell-padding: 1px !default; -$md-calendar-table-cell-content-size: 32px !default; -$md-calendar-table-cell-content-border-width: 1px !default; - - -.md-calendar-table-table { - border-spacing: 0; - font-size: $md-calendar-table-font-size; -} - -.md-calendar-table-label { - height: $md-calendar-table-cell-content-size; - padding: 0 0 0 10px; - text-align: left; - font-weight: normal; -} - -.md-calendar-table-cell { - padding: $md-calendar-table-cell-padding; -} - -.md-calendar-table-cell-content { - display: table-cell; - box-sizing: border-box; - width: $md-calendar-table-cell-content-size; - height: $md-calendar-table-cell-content-size; - border: $md-calendar-table-cell-content-border-width solid transparent; - border-radius: 50%; - text-align: center; - vertical-align: middle; -} - -[dir='rtl'] { - .md-calendar-table-label { - padding: 0 10px 0 0; - text-align: right; - } -} diff --git a/src/lib/date-picker/date-locale.ts b/src/lib/date-picker/date-locale.ts deleted file mode 100644 index c07dd2777e81..000000000000 --- a/src/lib/date-picker/date-locale.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** Date locale info. TODO(mmalerba): Integrate with i18n solution once we know what we're doing. */ -export class DateLocale { - firstDayOfWeek = 0; - - months = [ - { full: 'January', short: 'Jan' }, - { full: 'February', short: 'Feb' }, - { full: 'March', short: 'Mar' }, - { full: 'April', short: 'Apr' }, - { full: 'May', short: 'May' }, - { full: 'June', short: 'Jun' }, - { full: 'July', short: 'Jul' }, - { full: 'August', short: 'Aug' }, - { full: 'September', short: 'Sep' }, - { full: 'October', short: 'Oct' }, - { full: 'November', short: 'Nov' }, - { full: 'December', short: 'Dec' }, - ]; - - days = [ - { full: 'Sunday', short: 'Sun', xshort: 'S' }, - { full: 'Monday', short: 'Mon', xshort: 'M' }, - { full: 'Tuesday', short: 'Tue', xshort: 'T' }, - { full: 'Wednesday', short: 'Wed', xshort: 'W' }, - { full: 'Thursday', short: 'Thu', xshort: 'T' }, - { full: 'Friday', short: 'Fri', xshort: 'F' }, - { full: 'Saturday', short: 'Sat', xshort: 'S' }, - ]; - - getDateLabel(d: number) { return `${d}`; } - - getMonthLabel(m: number, y: number) { return `${this.months[m].short.toUpperCase()} ${y}`; } - - getYearLabel(y: number) { return `${y}`; } -} diff --git a/src/lib/date-picker/index.ts b/src/lib/date-picker/index.ts deleted file mode 100644 index 311e67811744..000000000000 --- a/src/lib/date-picker/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {NgModule, ModuleWithProviders} from '@angular/core'; -import {MdMonthView} from './month-view'; -import {DefaultStyleCompatibilityModeModule} from '../core/compatibility/default-mode'; -import {CommonModule} from '@angular/common'; -import {MdCalendarTable} from './calendar-table'; -import {DateLocale} from './date-locale'; -import {MdYearView} from './year-view'; - - -export * from './calendar-table'; -export * from './date-locale' -export * from './month-view'; -export * from './year-view'; - - -@NgModule({ - imports: [CommonModule, DefaultStyleCompatibilityModeModule], - exports: [MdCalendarTable, MdMonthView, MdYearView, DefaultStyleCompatibilityModeModule], - declarations: [MdCalendarTable, MdMonthView, MdYearView], - providers: [DateLocale] -}) -export class MdDatePickerModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: MdDatePickerModule, - providers: [DateLocale] - }; - } -} diff --git a/src/lib/date-picker/README.md b/src/lib/datepicker/README.md similarity index 69% rename from src/lib/date-picker/README.md rename to src/lib/datepicker/README.md index abcf6bd5669e..f206ff3f0b46 100644 --- a/src/lib/date-picker/README.md +++ b/src/lib/datepicker/README.md @@ -1,3 +1,3 @@ -# md-date-picker +# md-datepicker Work in progress, not ready for use. diff --git a/src/lib/date-picker/_date-picker-theme.scss b/src/lib/datepicker/_datepicker-theme.scss similarity index 68% rename from src/lib/date-picker/_date-picker-theme.scss rename to src/lib/datepicker/_datepicker-theme.scss index cc88bc96ec9d..af66d645fa60 100644 --- a/src/lib/date-picker/_date-picker-theme.scss +++ b/src/lib/datepicker/_datepicker-theme.scss @@ -2,28 +2,28 @@ @import '../core/theming/theming'; -@mixin md-date-picker-theme($theme) { +@mixin mat-datepicker-theme($theme) { $primary: map-get($theme, primary); $foreground: map-get($theme, foreground); $background: map-get($theme, background); - .md-calendar-table-label { + .mat-calendar-table-label { color: md-color($foreground, secondary-text); } - .md-calendar-table-cell-content { + .mat-calendar-table-cell-content { color: md-color($foreground, text); - .md-calendar-table-cell:hover & { + .mat-calendar-table-cell:hover & { background: md-color($background, hover); } - .md-calendar-table-cell &.md-calendar-table-selected { + .mat-calendar-table-cell &.mat-calendar-table-selected { background: md-color($primary); color: md-color($primary, default-contrast); } - &.md-calendar-table-today { + &.mat-calendar-table-today { border-color: md-color($foreground, divider); } } diff --git a/src/lib/date-picker/calendar-table.html b/src/lib/datepicker/calendar-table.html similarity index 59% rename from src/lib/date-picker/calendar-table.html rename to src/lib/datepicker/calendar-table.html index 830d93aa8471..6df7a677b4e4 100644 --- a/src/lib/date-picker/calendar-table.html +++ b/src/lib/datepicker/calendar-table.html @@ -1,22 +1,22 @@ - +
- + diff --git a/src/lib/datepicker/calendar-table.scss b/src/lib/datepicker/calendar-table.scss new file mode 100644 index 000000000000..f6c99a7df15e --- /dev/null +++ b/src/lib/datepicker/calendar-table.scss @@ -0,0 +1,39 @@ +$mat-calendar-table-font-size: 12px !default; +$mat-calendar-table-cell-padding: 1px !default; +$mat-calendar-table-cell-content-size: 32px !default; +$mat-calendar-table-cell-content-border-width: 1px !default; + + +.mat-calendar-table-table { + border-spacing: 0; + font-size: $mat-calendar-table-font-size; +} + +.mat-calendar-table-label { + height: $mat-calendar-table-cell-content-size; + padding: 0 0 0 10px; + text-align: left; + font-weight: normal; +} + +.mat-calendar-table-cell { + padding: $mat-calendar-table-cell-padding; +} + +.mat-calendar-table-cell-content { + display: table-cell; + box-sizing: border-box; + width: $mat-calendar-table-cell-content-size; + height: $mat-calendar-table-cell-content-size; + border: $mat-calendar-table-cell-content-border-width solid transparent; + border-radius: 50%; + text-align: center; + vertical-align: middle; +} + +[dir='rtl'] { + .mat-calendar-table-label { + padding: 0 10px 0 0; + text-align: right; + } +} diff --git a/src/lib/date-picker/calendar-table.spec.ts b/src/lib/datepicker/calendar-table.spec.ts similarity index 86% rename from src/lib/date-picker/calendar-table.spec.ts rename to src/lib/datepicker/calendar-table.spec.ts index ef4fc7dcab67..5137420e4437 100644 --- a/src/lib/date-picker/calendar-table.spec.ts +++ b/src/lib/datepicker/calendar-table.spec.ts @@ -1,5 +1,5 @@ import {async, TestBed, ComponentFixture} from '@angular/core/testing'; -import {MdDatePickerModule} from './index'; +import {MdDatepickerModule} from './index'; import {Component} from '@angular/core'; import {MdCalendarTable, MdCalendarCell} from './calendar-table'; import {By} from '@angular/platform-browser'; @@ -8,7 +8,7 @@ import {By} from '@angular/platform-browser'; describe('MdCalendarTable', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [MdDatePickerModule], + imports: [MdDatepickerModule], declarations: [ StandardCalendarTable, ], @@ -27,8 +27,8 @@ describe('MdCalendarTable', () => { let refreshElementLists = () => { rowEls = calendarTableNativeElement.querySelectorAll('tr'); - labelEls = calendarTableNativeElement.querySelectorAll('.md-calendar-table-label'); - cellEls = calendarTableNativeElement.querySelectorAll('.md-calendar-table-cell'); + labelEls = calendarTableNativeElement.querySelectorAll('.mat-calendar-table-label'); + cellEls = calendarTableNativeElement.querySelectorAll('.mat-calendar-table-cell'); }; beforeEach(() => { @@ -49,13 +49,13 @@ describe('MdCalendarTable', () => { }); it('highlights today', () => { - let todayCell = calendarTableNativeElement.querySelector('.md-calendar-table-today'); + let todayCell = calendarTableNativeElement.querySelector('.mat-calendar-table-today'); expect(todayCell).not.toBeNull(); expect(todayCell.innerHTML.trim()).toBe('3'); }); it('highlights selected', () => { - let todayCell = calendarTableNativeElement.querySelector('.md-calendar-table-selected'); + let todayCell = calendarTableNativeElement.querySelector('.mat-calendar-table-selected'); expect(todayCell).not.toBeNull(); expect(todayCell.innerHTML.trim()).toBe('4'); }); @@ -69,18 +69,18 @@ describe('MdCalendarTable', () => { expect(rowEls.length).toBe(2); expect(labelEls.length).toBe(1); expect(cellEls.length).toBe(11); - expect(rowEls[0].firstElementChild.classList.contains('md-calendar-table-label')).toBe( + expect(rowEls[0].firstElementChild.classList.contains('mat-calendar-table-label')).toBe( true, 'first cell should be the label'); expect(labelEls[0].getAttribute('colspan')).toBe('3'); }); it('cell should be selected on click', () => { let todayElement = - calendarTableNativeElement.querySelector('.md-calendar-table-today') as HTMLElement; + calendarTableNativeElement.querySelector('.mat-calendar-table-today') as HTMLElement; todayElement.click(); fixture.detectChanges(); - expect(todayElement.classList.contains('md-calendar-table-selected')).toBe( + expect(todayElement.classList.contains('mat-calendar-table-selected')).toBe( true, 'today should be selected'); }); }); diff --git a/src/lib/date-picker/calendar-table.ts b/src/lib/datepicker/calendar-table.ts similarity index 99% rename from src/lib/date-picker/calendar-table.ts rename to src/lib/datepicker/calendar-table.ts index 2df28f6b4378..70999010cbd5 100644 --- a/src/lib/date-picker/calendar-table.ts +++ b/src/lib/datepicker/calendar-table.ts @@ -8,7 +8,6 @@ import { } from '@angular/core'; - /** * An internal class that represents the data corresponding to a single calendar cell. * @docs-private diff --git a/src/lib/datepicker/index.ts b/src/lib/datepicker/index.ts new file mode 100644 index 000000000000..05eafc0cf9bf --- /dev/null +++ b/src/lib/datepicker/index.ts @@ -0,0 +1,19 @@ +import {NgModule} from '@angular/core'; +import {MdMonthView} from './month-view'; +import {CommonModule} from '@angular/common'; +import {MdCalendarTable} from './calendar-table'; +import {MdYearView} from './year-view'; +import {DatetimeModule} from '../core/datetime/index'; + + +export * from './calendar-table'; +export * from './month-view'; +export * from './year-view'; + + +@NgModule({ + imports: [CommonModule, DatetimeModule], + exports: [MdCalendarTable, MdMonthView, MdYearView], + declarations: [MdCalendarTable, MdMonthView, MdYearView], +}) +export class MdDatepickerModule {} diff --git a/src/lib/date-picker/month-view.html b/src/lib/datepicker/month-view.html similarity index 100% rename from src/lib/date-picker/month-view.html rename to src/lib/datepicker/month-view.html diff --git a/src/lib/date-picker/month-view.spec.ts b/src/lib/datepicker/month-view.spec.ts similarity index 61% rename from src/lib/date-picker/month-view.spec.ts rename to src/lib/datepicker/month-view.spec.ts index 161cc6eee8fc..2094eecf273a 100644 --- a/src/lib/date-picker/month-view.spec.ts +++ b/src/lib/datepicker/month-view.spec.ts @@ -1,14 +1,15 @@ import {async, TestBed, ComponentFixture} from '@angular/core/testing'; -import {MdDatePickerModule} from './index'; +import {MdDatepickerModule} from './index'; import {Component} from '@angular/core'; import {By} from '@angular/platform-browser'; import {MdMonthView} from './month-view'; +import {SimpleDate} from '../core/datetime/simple-date'; describe('MdMonthView', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [MdDatePickerModule], + imports: [MdDatepickerModule], declarations: [ StandardMonthView, ], @@ -32,34 +33,34 @@ describe('MdMonthView', () => { }); it('has correct year label', () => { - let labelEl = monthViewNativeElement.querySelector('.md-calendar-table-label'); - expect(labelEl.innerHTML.trim()).toBe('JAN 2017'); + let labelEl = monthViewNativeElement.querySelector('.mat-calendar-table-label'); + expect(labelEl.innerHTML.trim()).toBe('Jan 2017'); }); it('has 31 days', () => { - let cellEls = monthViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + let cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-table-cell'); expect(cellEls.length).toBe(31); }); it('shows selected date if in same month', () => { - let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = monthViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl.innerHTML.trim()).toBe('10'); }); it('does not show selected date if in different month', () => { - testComponent.selected = new Date('3/10/2017'); + testComponent.selected = new SimpleDate(2017, 2, 10); fixture.detectChanges(); - let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = monthViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl).toBeNull(); }); it('fires selected change event on cell clicked', () => { - let cellEls = monthViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + let cellEls = monthViewNativeElement.querySelectorAll('.mat-calendar-table-cell'); (cellEls[cellEls.length - 1] as HTMLElement).click(); fixture.detectChanges(); - let selectedEl = monthViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = monthViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl.innerHTML.trim()).toBe('31'); }); }); @@ -67,12 +68,9 @@ describe('MdMonthView', () => { @Component({ - template: ` - `, + template: ``, }) class StandardMonthView { - date = new Date('1/5/2017'); - selected = new Date('1/10/2017'); + date = new SimpleDate(2017, 0, 5); + selected = new SimpleDate(2017, 0, 10); } diff --git a/src/lib/date-picker/month-view.ts b/src/lib/datepicker/month-view.ts similarity index 64% rename from src/lib/date-picker/month-view.ts rename to src/lib/datepicker/month-view.ts index 2a6be9f08220..f0bfd18a4c50 100644 --- a/src/lib/date-picker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -7,16 +7,16 @@ import { Output, AfterContentInit } from '@angular/core'; -import {coerceDateProperty} from '../core/coercion/date-property'; import {MdCalendarCell} from './calendar-table'; -import {DateLocale} from './date-locale'; +import {CalendarLocale} from '../core/datetime/calendar-locale'; +import {SimpleDate} from '../core/datetime/simple-date'; const DAYS_PER_WEEK = 7; /** - * An internal component used to display a single month in the date-picker. + * An internal component used to display a single month in the datepicker. * @docs-private */ @Component({ @@ -33,22 +33,22 @@ export class MdMonthView implements AfterContentInit { @Input() get date() { return this._date; } set date(value) { - this._date = coerceDateProperty(value); + this._date = this._locale.parseDate(value) || SimpleDate.fromNativeDate(new Date()); this._init(); } - private _date = new Date(); + private _date = SimpleDate.fromNativeDate(new Date()); /** The currently selected date. */ @Input() get selected() { return this._selected; } set selected(value) { - this._selected = coerceDateProperty(value, null); + this._selected = this._locale.parseDate(value); this._selectedDate = this._getDateInCurrentMonth(this.selected); } - private _selected: Date; + private _selected: SimpleDate; /** Emits when a new date is selected. */ - @Output() selectedChange = new EventEmitter(); + @Output() selectedChange = new EventEmitter(); /** The label for this month (e.g. "January 2017"). */ _monthLabel: string; @@ -68,7 +68,7 @@ export class MdMonthView implements AfterContentInit { /** The date of the month that today falls on. Null if today is in another month. */ _todayDate = 0; - constructor(private _locale: DateLocale) {} + constructor(private _locale: CalendarLocale) {} ngAfterContentInit(): void { this._init(); @@ -76,36 +76,38 @@ export class MdMonthView implements AfterContentInit { /** Handles when a new date is selected. */ _dateSelected(date: number) { - if (this.selected && this.selected.getDate() == date) { + if (this.selected && this.selected.date == date) { return; } - this.selectedChange.emit(new Date(this.date.getFullYear(), this.date.getMonth(), date)); + this.selectedChange.emit(new SimpleDate(this.date.year, this.date.month, date)); } /** Initializes this month view. */ private _init() { this._selectedDate = this._getDateInCurrentMonth(this.selected); - this._todayDate = this._getDateInCurrentMonth(new Date()); - this._monthLabel = this._locale.getMonthLabel(this.date.getMonth(), this.date.getFullYear()); + this._todayDate = this._getDateInCurrentMonth(SimpleDate.fromNativeDate(new Date())); + this._monthLabel = this._locale.getCalendarMonthHeaderLabel(this.date); - let firstOfMonth = new Date(this.date.getFullYear(), this.date.getMonth(), 1); + let firstOfMonth = new SimpleDate(this.date.year, this.date.month, 1); this._firstWeekOffset = - (DAYS_PER_WEEK + firstOfMonth.getDay() - this._locale.firstDayOfWeek) % DAYS_PER_WEEK; + (DAYS_PER_WEEK + firstOfMonth.toNativeDate().getDay() - this._locale.firstDayOfWeek) % + DAYS_PER_WEEK; this._createWeekCells(); } /** Creates MdCalendarCells for the dates in this month. */ private _createWeekCells() { - let daysInMonth = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0).getDate(); + let daysInMonth = + new SimpleDate(this.date.year, this.date.month + 1, 0).toNativeDate().getDate(); this._weeks = [[]]; for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { if (cell == DAYS_PER_WEEK) { this._weeks.push([]); cell = 0; } - this._weeks[this._weeks.length - 1].push( - new MdCalendarCell(i + 1, this._locale.getDateLabel(i + 1))); + this._weeks[this._weeks.length - 1] + .push(new MdCalendarCell(i + 1, this._locale.dates[i + 1])); } } @@ -113,7 +115,7 @@ export class MdMonthView implements AfterContentInit { * Gets the date in this month that the given Date falls on. * Returns null if the given Date is in another year. */ - private _getDateInCurrentMonth(date: Date) { - return date && date.getMonth() == this.date.getMonth() ? date.getDate() : null; + private _getDateInCurrentMonth(date: SimpleDate) { + return date && date.month == this.date.month ? date.date : null; } } diff --git a/src/lib/date-picker/year-view.html b/src/lib/datepicker/year-view.html similarity index 100% rename from src/lib/date-picker/year-view.html rename to src/lib/datepicker/year-view.html diff --git a/src/lib/date-picker/year-view.spec.ts b/src/lib/datepicker/year-view.spec.ts similarity index 63% rename from src/lib/date-picker/year-view.spec.ts rename to src/lib/datepicker/year-view.spec.ts index 736d9442b5fb..a60febe29320 100644 --- a/src/lib/date-picker/year-view.spec.ts +++ b/src/lib/datepicker/year-view.spec.ts @@ -1,14 +1,15 @@ import {async, TestBed, ComponentFixture} from '@angular/core/testing'; -import {MdDatePickerModule} from './index'; +import {MdDatepickerModule} from './index'; import {Component} from '@angular/core'; import {By} from '@angular/platform-browser'; import {MdYearView} from './year-view'; +import {SimpleDate} from '../core/datetime/simple-date'; describe('MdYearView', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [MdDatePickerModule], + imports: [MdDatepickerModule], declarations: [ StandardYearView, ], @@ -32,34 +33,34 @@ describe('MdYearView', () => { }); it('has correct year label', () => { - let labelEl = yearViewNativeElement.querySelector('.md-calendar-table-label'); + let labelEl = yearViewNativeElement.querySelector('.mat-calendar-table-label'); expect(labelEl.innerHTML.trim()).toBe('2017'); }); it('has 12 months', () => { - let cellEls = yearViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + let cellEls = yearViewNativeElement.querySelectorAll('.mat-calendar-table-cell'); expect(cellEls.length).toBe(12); }); it('shows selected month if in same year', () => { - let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = yearViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl.innerHTML.trim()).toBe('Mar'); }); it('does not show selected month if in different year', () => { - testComponent.selected = new Date('3/10/2016'); + testComponent.selected = new SimpleDate(2016, 2, 10); fixture.detectChanges(); - let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = yearViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl).toBeNull(); }); it('fires selected change event on cell clicked', () => { - let cellEls = yearViewNativeElement.querySelectorAll('.md-calendar-table-cell'); + let cellEls = yearViewNativeElement.querySelectorAll('.mat-calendar-table-cell'); (cellEls[cellEls.length - 1] as HTMLElement).click(); fixture.detectChanges(); - let selectedEl = yearViewNativeElement.querySelector('.md-calendar-table-selected'); + let selectedEl = yearViewNativeElement.querySelector('.mat-calendar-table-selected'); expect(selectedEl.innerHTML.trim()).toBe('Dec'); }); }); @@ -67,12 +68,9 @@ describe('MdYearView', () => { @Component({ - template: ` - `, + template: ``, }) class StandardYearView { - date = new Date('1/5/2017'); - selected = new Date('3/10/2017'); + date = new SimpleDate(2017, 0, 5); + selected = new SimpleDate(2017, 2, 10); } diff --git a/src/lib/date-picker/year-view.ts b/src/lib/datepicker/year-view.ts similarity index 69% rename from src/lib/date-picker/year-view.ts rename to src/lib/datepicker/year-view.ts index da0363ac30da..666158ac0d31 100644 --- a/src/lib/date-picker/year-view.ts +++ b/src/lib/datepicker/year-view.ts @@ -7,13 +7,13 @@ import { Output, EventEmitter } from '@angular/core'; -import {DateLocale} from './date-locale'; -import {coerceDateProperty} from '../core/coercion/date-property'; import {MdCalendarCell} from './calendar-table'; +import {CalendarLocale} from '../core/datetime/calendar-locale'; +import {SimpleDate} from '../core/datetime/simple-date'; /** - * An internal component used to display a single year in the date-picker. + * An internal component used to display a single year in the datepicker. * @docs-private */ @Component({ @@ -28,22 +28,22 @@ export class MdYearView implements AfterContentInit { @Input() get date() { return this._date; } set date(value) { - this._date = coerceDateProperty(value); + this._date = this._locale.parseDate(value) || SimpleDate.fromNativeDate(new Date()); this._init(); } - private _date = new Date(); + private _date = SimpleDate.fromNativeDate(new Date()); /** The currently selected date. */ @Input() get selected() { return this._selected; } set selected(value) { - this._selected = coerceDateProperty(value, null); + this._selected = this._locale.parseDate(value); this._selectedMonth = this._getMonthInCurrentYear(this.selected); } - private _selected: Date; + private _selected: SimpleDate; /** Emits when a new month is selected. */ - @Output() selectedChange = new EventEmitter(); + @Output() selectedChange = new EventEmitter(); /** Grid of calendar cells representing the months of the year. */ _months: MdCalendarCell[][]; @@ -60,7 +60,7 @@ export class MdYearView implements AfterContentInit { */ _selectedMonth: number; - constructor(private _locale: DateLocale) { + constructor(private _locale: CalendarLocale) { // First row of months only contains 5 elements so we can fit the year label on the same row. this._months = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11]].map(row => row.map( month => this._createCellForMonth(month))); @@ -72,29 +72,29 @@ export class MdYearView implements AfterContentInit { /** Handles when a new month is selected. */ _monthSelected(month: number) { - if (this.selected && this.selected.getMonth() == month) { + if (this.selected && this.selected.month == month) { return; } - this.selectedChange.emit(new Date(this.date.getFullYear(), month, 1)); + this.selectedChange.emit(new SimpleDate(this.date.year, month, 1)); } /** Initializes this month view. */ private _init() { this._selectedMonth = this._getMonthInCurrentYear(this.selected); - this._todayMonth = this._getMonthInCurrentYear(new Date()); - this._yearLabel = this._locale.getYearLabel(this._date.getFullYear()); + this._todayMonth = this._getMonthInCurrentYear(SimpleDate.fromNativeDate(new Date())); + this._yearLabel = this._locale.getCalendarYearHeaderLabel(this._date); } /** * Gets the month in this year that the given Date falls on. * Returns null if the given Date is in another year. */ - private _getMonthInCurrentYear(date: Date) { - return date && date.getFullYear() == this.date.getFullYear() ? date.getMonth() : null; + private _getMonthInCurrentYear(date: SimpleDate) { + return date && date.year == this.date.year ? date.month : null; } /** Creates an MdCalendarCell for the given month. */ private _createCellForMonth(month: number) { - return new MdCalendarCell(month, this._locale.months[month].short); + return new MdCalendarCell(month, this._locale.shortMonths[month]); } } diff --git a/src/lib/index.ts b/src/lib/index.ts index 24420b24504c..8cba88e38106 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -6,7 +6,7 @@ export * from './button-toggle/index'; export * from './card/index'; export * from './chips/index'; export * from './checkbox/index'; -export * from './date-picker/index'; +export * from './datepicker/index'; export * from './dialog/index'; export * from './grid-list/index'; export * from './icon/index'; diff --git a/src/lib/module.ts b/src/lib/module.ts index 15065a9d1356..32e7cc230e81 100644 --- a/src/lib/module.ts +++ b/src/lib/module.ts @@ -36,7 +36,7 @@ import {MdMenuModule} from './menu/index'; import {MdDialogModule} from './dialog/index'; import {PlatformModule} from './core/platform/index'; import {MdAutocompleteModule} from './autocomplete/index'; -import {MdDatePickerModule} from './date-picker/index'; +import {MdDatepickerModule} from './datepicker/index'; const MATERIAL_MODULES = [ MdAutocompleteModule, @@ -45,7 +45,7 @@ const MATERIAL_MODULES = [ MdCardModule, MdChipsModule, MdCheckboxModule, - MdDatePickerModule, + MdDatepickerModule, MdDialogModule, MdGridListModule, MdIconModule, @@ -82,7 +82,6 @@ const MATERIAL_MODULES = [ MdCardModule.forRoot(), MdChipsModule.forRoot(), MdCheckboxModule.forRoot(), - MdDatePickerModule.forRoot(), MdGridListModule.forRoot(), MdInputModule.forRoot(), MdListModule.forRoot(), From 3914d1d3258bebc147d617c18452577d8e0fc1d9 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 2 Feb 2017 11:09:10 -0800 Subject: [PATCH 16/19] add some additional functionality to SimpleDate --- src/demo-app/datepicker/datepicker-demo.ts | 2 +- src/lib/core/datetime/simple-date.spec.ts | 28 ++++++++++++ src/lib/core/datetime/simple-date.ts | 53 +++++++++++++++++++++- src/lib/datepicker/month-view.ts | 12 ++--- src/lib/datepicker/year-view.ts | 6 +-- 5 files changed, 89 insertions(+), 12 deletions(-) diff --git a/src/demo-app/datepicker/datepicker-demo.ts b/src/demo-app/datepicker/datepicker-demo.ts index f0d32f6bb24a..38c4e8247c3c 100644 --- a/src/demo-app/datepicker/datepicker-demo.ts +++ b/src/demo-app/datepicker/datepicker-demo.ts @@ -8,6 +8,6 @@ import {SimpleDate} from '@angular/material'; templateUrl: 'datepicker-demo.html' }) export class DatepickerDemo { - date = SimpleDate.fromNativeDate(new Date()); + date = SimpleDate.today(); selected: SimpleDate; } diff --git a/src/lib/core/datetime/simple-date.spec.ts b/src/lib/core/datetime/simple-date.spec.ts index bbb69e00fc40..e47dead290bc 100644 --- a/src/lib/core/datetime/simple-date.spec.ts +++ b/src/lib/core/datetime/simple-date.spec.ts @@ -9,4 +9,32 @@ describe('SimpleDate', () => { it('can be converted to native Date', () => { expect(new SimpleDate(2017, 0, 1).toNativeDate()).toEqual(new Date(2017, 0, 1)); }); + + it('handles month and date overflow', () => { + expect(new SimpleDate(2017, 12, 32)).toEqual(new SimpleDate(2018, 1, 1)); + }); + + it('handles month and date underflow', () => { + expect(new SimpleDate(2017, -1, 0)).toEqual(new SimpleDate(2016, 10, 30)); + }); + + it('handles low year numbers', () => { + expect(new SimpleDate(-1, 0, 1).year).toBe(-1); + expect(new SimpleDate(0, 0, 1).year).toBe(0); + expect(new SimpleDate(50, 0, 1).year).toBe(50); + expect(new SimpleDate(99, 0, 1).year).toBe(99); + expect(new SimpleDate(100, 0, 1).year).toBe(100); + }); + + it('handles low year number with over/under-flow', () => { + expect(new SimpleDate(50, 12 * 51, 1).year).toBe(101); + expect(new SimpleDate(50, 12, 1).year).toBe(51); + expect(new SimpleDate(50, -12, 1).year).toBe(49); + expect(new SimpleDate(50, -12 * 51, 1).year).toBe(-1); + }); + + it('adds years, months, and days', () => { + expect(new SimpleDate(2017, 0, 1).add({years: 1, months: 1, days: 1})) + .toEqual(new SimpleDate(2018, 1, 2)); + }); }); diff --git a/src/lib/core/datetime/simple-date.ts b/src/lib/core/datetime/simple-date.ts index 6fbe28a2a4fd..41874863c7e1 100644 --- a/src/lib/core/datetime/simple-date.ts +++ b/src/lib/core/datetime/simple-date.ts @@ -3,12 +3,63 @@ * details and the time component of the native Date. */ export class SimpleDate { + /** + * Create a SimpleDate from a native JS Date object. + * @param nativeDate The native JS Date object to convert. + */ static fromNativeDate(nativeDate: Date) { return new SimpleDate(nativeDate.getFullYear(), nativeDate.getMonth(), nativeDate.getDate()); } - constructor(public year: number, public month: number, public date: number) {} + /** Creates a SimpleDate object representing today. */ + static today() { + return SimpleDate.fromNativeDate(new Date()); + } + + /** The native JS Date. */ + private _date: Date; + + constructor(year: number, month: number, date: number) { + this._date = new Date(year, month, date); + // We need to correct for the fact that JS native Date treats years in range [0, 99] as + // abbreviations for 19xx. + if (year >= 0 && year < 100) { + this._date = new Date(this._date.setFullYear(this.year - 1900)); + } + } + + /** The year component of this date. */ + get year() { + return this._date.getFullYear(); + } + + /** The month component of this date. */ + get month() { + return this._date.getMonth(); + } + + /** The date component of this date. */ + get date() { + return this._date.getDate(); + } + + /** The day component of this date. */ + get day() { + return this._date.getDay(); + } + + /** + * Adds an amount of time (in days, months, and years) to the date. + * @param amount The amount of time to add. + */ + add(amount: {days: number, months: number, years: number}) { + return new SimpleDate( + this.year + amount.years || 0, + this.month + amount.months || 0, + this.date + amount.days || 0); + } + /** Converts the SimpleDate to a native JS Date object. */ toNativeDate() { return new Date(this.year, this.month, this.date); } diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index f0bfd18a4c50..20e7120acce0 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -33,10 +33,10 @@ export class MdMonthView implements AfterContentInit { @Input() get date() { return this._date; } set date(value) { - this._date = this._locale.parseDate(value) || SimpleDate.fromNativeDate(new Date()); + this._date = this._locale.parseDate(value) || SimpleDate.today(); this._init(); } - private _date = SimpleDate.fromNativeDate(new Date()); + private _date = SimpleDate.today(); /** The currently selected date. */ @Input() @@ -85,21 +85,19 @@ export class MdMonthView implements AfterContentInit { /** Initializes this month view. */ private _init() { this._selectedDate = this._getDateInCurrentMonth(this.selected); - this._todayDate = this._getDateInCurrentMonth(SimpleDate.fromNativeDate(new Date())); + this._todayDate = this._getDateInCurrentMonth(SimpleDate.today()); this._monthLabel = this._locale.getCalendarMonthHeaderLabel(this.date); let firstOfMonth = new SimpleDate(this.date.year, this.date.month, 1); this._firstWeekOffset = - (DAYS_PER_WEEK + firstOfMonth.toNativeDate().getDay() - this._locale.firstDayOfWeek) % - DAYS_PER_WEEK; + (DAYS_PER_WEEK + firstOfMonth.day - this._locale.firstDayOfWeek) % DAYS_PER_WEEK; this._createWeekCells(); } /** Creates MdCalendarCells for the dates in this month. */ private _createWeekCells() { - let daysInMonth = - new SimpleDate(this.date.year, this.date.month + 1, 0).toNativeDate().getDate(); + let daysInMonth = new SimpleDate(this.date.year, this.date.month + 1, 0).date; this._weeks = [[]]; for (let i = 0, cell = this._firstWeekOffset; i < daysInMonth; i++, cell++) { if (cell == DAYS_PER_WEEK) { diff --git a/src/lib/datepicker/year-view.ts b/src/lib/datepicker/year-view.ts index 666158ac0d31..7521103f73fa 100644 --- a/src/lib/datepicker/year-view.ts +++ b/src/lib/datepicker/year-view.ts @@ -28,10 +28,10 @@ export class MdYearView implements AfterContentInit { @Input() get date() { return this._date; } set date(value) { - this._date = this._locale.parseDate(value) || SimpleDate.fromNativeDate(new Date()); + this._date = this._locale.parseDate(value) || SimpleDate.today(); this._init(); } - private _date = SimpleDate.fromNativeDate(new Date()); + private _date = SimpleDate.today(); /** The currently selected date. */ @Input() @@ -81,7 +81,7 @@ export class MdYearView implements AfterContentInit { /** Initializes this month view. */ private _init() { this._selectedMonth = this._getMonthInCurrentYear(this.selected); - this._todayMonth = this._getMonthInCurrentYear(SimpleDate.fromNativeDate(new Date())); + this._todayMonth = this._getMonthInCurrentYear(SimpleDate.today()); this._yearLabel = this._locale.getCalendarYearHeaderLabel(this._date); } From 2d6b58f767e84af73722168e2f37b9f95ee3d025 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 2 Feb 2017 11:12:10 -0800 Subject: [PATCH 17/19] fix lint --- src/lib/core/datetime/calendar-locale.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/datetime/calendar-locale.spec.ts b/src/lib/core/datetime/calendar-locale.spec.ts index 455e2a68cae0..d37b0e072e9b 100644 --- a/src/lib/core/datetime/calendar-locale.spec.ts +++ b/src/lib/core/datetime/calendar-locale.spec.ts @@ -101,5 +101,5 @@ describe('DefaultCalendarLocale', () => { it('gets header label for calendar year', () => { expect(calendarLocale.getCalendarYearHeaderLabel(new SimpleDate(2017, 0, 1))).toBe('2017'); - }) + }); }); From 38c5a9ae67a660e22f65f798f41ff2ecfc7bda71 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 2 Feb 2017 17:23:24 -0800 Subject: [PATCH 18/19] addressed comments --- src/lib/core/datetime/simple-date.ts | 4 ++-- src/lib/datepicker/calendar-table.spec.ts | 6 +++--- src/lib/datepicker/month-view.spec.ts | 2 +- src/lib/datepicker/month-view.ts | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/core/datetime/simple-date.ts b/src/lib/core/datetime/simple-date.ts index 41874863c7e1..6c6397b08ed0 100644 --- a/src/lib/core/datetime/simple-date.ts +++ b/src/lib/core/datetime/simple-date.ts @@ -33,7 +33,7 @@ export class SimpleDate { return this._date.getFullYear(); } - /** The month component of this date. */ + /** The month component of this date. (0-indexed, 0 = January). */ get month() { return this._date.getMonth(); } @@ -43,7 +43,7 @@ export class SimpleDate { return this._date.getDate(); } - /** The day component of this date. */ + /** The day component of this date. (0-indexed, 0 = Sunday) */ get day() { return this._date.getDay(); } diff --git a/src/lib/datepicker/calendar-table.spec.ts b/src/lib/datepicker/calendar-table.spec.ts index 5137420e4437..a7f12e786d3f 100644 --- a/src/lib/datepicker/calendar-table.spec.ts +++ b/src/lib/datepicker/calendar-table.spec.ts @@ -55,9 +55,9 @@ describe('MdCalendarTable', () => { }); it('highlights selected', () => { - let todayCell = calendarTableNativeElement.querySelector('.mat-calendar-table-selected'); - expect(todayCell).not.toBeNull(); - expect(todayCell.innerHTML.trim()).toBe('4'); + let selectedCell = calendarTableNativeElement.querySelector('.mat-calendar-table-selected'); + expect(selectedCell).not.toBeNull(); + expect(selectedCell.innerHTML.trim()).toBe('4'); }); it('places label in first row if space is available', () => { diff --git a/src/lib/datepicker/month-view.spec.ts b/src/lib/datepicker/month-view.spec.ts index 2094eecf273a..c9a7badd5f92 100644 --- a/src/lib/datepicker/month-view.spec.ts +++ b/src/lib/datepicker/month-view.spec.ts @@ -18,7 +18,7 @@ describe('MdMonthView', () => { TestBed.compileComponents(); })); - describe('standard year view', () => { + describe('standard month view', () => { let fixture: ComponentFixture; let testComponent: StandardMonthView; let monthViewNativeElement: Element; diff --git a/src/lib/datepicker/month-view.ts b/src/lib/datepicker/month-view.ts index 20e7120acce0..fbfc0c0d7d8c 100644 --- a/src/lib/datepicker/month-view.ts +++ b/src/lib/datepicker/month-view.ts @@ -63,10 +63,10 @@ export class MdMonthView implements AfterContentInit { * The date of the month that the currently selected Date falls on. * Null if the currently selected Date is in another month. */ - _selectedDate = 0; + _selectedDate: number; /** The date of the month that today falls on. Null if today is in another month. */ - _todayDate = 0; + _todayDate: number; constructor(private _locale: CalendarLocale) {} @@ -111,7 +111,7 @@ export class MdMonthView implements AfterContentInit { /** * Gets the date in this month that the given Date falls on. - * Returns null if the given Date is in another year. + * Returns null if the given Date is in another month. */ private _getDateInCurrentMonth(date: SimpleDate) { return date && date.month == this.date.month ? date.date : null; From e3c0dae988130ba3c276b9fdb5148b8b272e52d8 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Fri, 3 Feb 2017 16:08:58 -0800 Subject: [PATCH 19/19] add comment --- src/lib/core/datetime/simple-date.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/datetime/simple-date.ts b/src/lib/core/datetime/simple-date.ts index 6c6397b08ed0..29e19338162d 100644 --- a/src/lib/core/datetime/simple-date.ts +++ b/src/lib/core/datetime/simple-date.ts @@ -38,7 +38,7 @@ export class SimpleDate { return this._date.getMonth(); } - /** The date component of this date. */ + /** The date component of this date. (1-indexed, 1 = 1st of month). */ get date() { return this._date.getDate(); }
{{label}}{{label}}
{{_firstRowOffset >= labelMinRequiredCells ? label : ''}} -
+
{{item.displayValue}}