Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(datepicker): merge datepicker branch into master #4404

Merged
merged 37 commits into from
May 12, 2017
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
869d0f2
create SimpleDate and CalendarLocale objects (#2839)
mmalerba Feb 2, 2017
4347689
feat(datepicker): add month & year view (#2904)
mmalerba Feb 7, 2017
fc34721
fixes i forgot to push before merging #2904 (#2978)
mmalerba Feb 8, 2017
e24f0ce
feat(datepicker): create the md-datepicker component (#3024)
mmalerba Feb 10, 2017
16a16c6
feat(datepicker): make calendar responsive (#3086)
mmalerba Feb 14, 2017
bcff6be
feat(datepicker): add calendar component that pulls together month an…
mmalerba Feb 14, 2017
58456ea
fix(datepicker): make calendar look more like mocks (#3138)
mmalerba Feb 17, 2017
bc4b168
add the calendar to the datepicker popup (#3178)
mmalerba Feb 19, 2017
08ccf03
feat(datepicker): wire up selected value propagation (#3330)
mmalerba Mar 3, 2017
4c20c5f
feat(datepicker): add md-datepicker-trigger & compatibility w/ md-inp…
mmalerba Mar 9, 2017
991cdde
feat(datepicker): add aria-* attrs and keyboard bindings to datepicke…
mmalerba Mar 10, 2017
4aeca6c
feat(datepicker): min & max dates + dateFilter (#3556)
mmalerba Mar 14, 2017
e6cf1ef
fix(datepicker): fix bug where calendar dialog could only be opened o…
mmalerba Mar 20, 2017
12076e8
feat(datepicker): add keyboard support to calendar (#3655)
mmalerba Mar 24, 2017
21cb164
angular 4 fixes
mmalerba Mar 28, 2017
dbb8387
fix(datepicker): use input's min & max properites rather than custom …
mmalerba Mar 30, 2017
559880d
fix(datepicker): hide weekdays in year view (#3852)
mmalerba Apr 10, 2017
a85c094
fix(datepicker): calendar should update when input changes (#3824)
mmalerba Apr 11, 2017
531f452
fix(datepicker): set focus properly when opening datepicker (#3839)
mmalerba Apr 14, 2017
1e9dfbd
fix(datepicker): make touch UI work well on mobile (#3853)
mmalerba Apr 14, 2017
776a10a
fix lint issues
mmalerba Apr 14, 2017
5f39247
fix(datepicker): some misc cleanup (#4106)
mmalerba Apr 17, 2017
8b6780c
refactor(datepicker): move weekdays into table header (#4129)
mmalerba Apr 19, 2017
f229b1b
feat(datepicker): add DateAdapter and NativeDateAdapter (#4148)
mmalerba Apr 20, 2017
9ab583a
refactor(datepicker): replace SimpleDate & CalendarLocale with DateAd…
mmalerba Apr 21, 2017
cb8a49d
datepicker: create injectable for date formats and bundle it along wi…
mmalerba Apr 27, 2017
2642715
fix lint issues
mmalerba Apr 29, 2017
ac706fe
fix(datepicker): make datepicker work with screen readers (#4349)
mmalerba May 2, 2017
a6428e5
docs(datepicker): update readme & demo (#4368)
mmalerba May 3, 2017
7964052
fix(datepicker): require actual date objects for min, max, etc (#4381)
mmalerba May 3, 2017
14b2523
feat(datepicker): input validation for min, max, and date filter (#4393)
mmalerba May 5, 2017
7fe110a
refactor(datepicker): migrate from Renderer to Renderer2
mmalerba May 5, 2017
361a05b
fix tests on safari 9
mmalerba May 8, 2017
4f5ccb2
fix Edge/IE tests that fail because of different Intl implementation
mmalerba May 8, 2017
9bbed07
strip direction characters when formatting
mmalerba May 9, 2017
0697350
fix lint
mmalerba May 9, 2017
3b31d7b
addressed comments
mmalerba May 10, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions src/demo-app/datepicker/datepicker-demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<h2>Options</h2>
<p>
<md-checkbox [(ngModel)]="touch">Use touch UI</md-checkbox>
<md-checkbox [(ngModel)]="filterOdd">Filter odd months and dates</md-checkbox>
<md-checkbox [(ngModel)]="yearView">Start in year view</md-checkbox>
</p>
<p>
<md-input-container>
<input mdInput [mdDatepicker]="minDatePicker" [(ngModel)]="minDate" placeholder="Min date">
<button mdSuffix [mdDatepickerToggle]="minDatePicker"></button>
</md-input-container>
<md-datepicker #minDatePicker [touchUi]="touch"></md-datepicker>
<md-input-container>
<input mdInput [mdDatepicker]="maxDatePicker" [(ngModel)]="maxDate" placeholder="Max date">
<button mdSuffix [mdDatepickerToggle]="maxDatePicker"></button>
</md-input-container>
<md-datepicker #maxDatePicker [touchUi]="touch"></md-datepicker>
</p>
<p>
<md-input-container>
<input mdInput [mdDatepicker]="startAtPicker" [(ngModel)]="startAt" placeholder="Start at date">
<button mdSuffix [mdDatepickerToggle]="startAtPicker"></button>
</md-input-container>
<md-datepicker #startAtPicker [touchUi]="touch"></md-datepicker>
</p>

<h2>Result</h2>

<p>
<button [mdDatepickerToggle]="resultPicker"></button>
<md-input-container>
<input mdInput
#resultPickerModel="ngModel"
[mdDatepicker]="resultPicker"
[(ngModel)]="date"
[min]="minDate"
[max]="maxDate"
[mdDatepickerFilter]="filterOdd ? dateFilter : null"
placeholder="Pick a date">
<md-error *ngIf="resultPickerModel.hasError('mdDatepickerMin')">Too early!</md-error>
<md-error *ngIf="resultPickerModel.hasError('mdDatepickerMax')">Too late!</md-error>
<md-error *ngIf="resultPickerModel.hasError('mdDatepickerFilter')">Date unavailable!</md-error>
</md-input-container>
<md-datepicker
#resultPicker
[touchUi]="touch"
[startAt]="startAt"
[startView]="yearView ? 'year' : 'month'">
</md-datepicker>
</p>
<p>
<input [mdDatepicker]="resultPicker2"
[(ngModel)]="date"
[min]="minDate"
[max]="maxDate"
[mdDatepickerFilter]="filterOdd ? dateFilter : null"
placeholder="Pick a date">
<button [mdDatepickerToggle]="resultPicker2"></button>
<md-datepicker
#resultPicker2
[touchUi]="touch"
[startAt]="startAt"
[startView]="yearView ? 'year' : 'month'">
</md-datepicker>
</p>
3 changes: 3 additions & 0 deletions src/demo-app/datepicker/datepicker-demo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
md-calendar {
width: 300px;
}
19 changes: 19 additions & 0 deletions src/demo-app/datepicker/datepicker-demo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Component} from '@angular/core';


@Component({
moduleId: module.id,
selector: 'datepicker-demo',
templateUrl: 'datepicker-demo.html',
styleUrls: ['datepicker-demo.css'],
})
export class DatepickerDemo {
touch: boolean;
filterOdd: boolean;
yearView: boolean;
minDate: Date;
maxDate: Date;
startAt: Date;
date: Date;
dateFilter = (date: Date) => date.getMonth() % 2 == 1 && date.getDate() % 2 == 0;
}
18 changes: 11 additions & 7 deletions src/demo-app/demo-app-module.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import {NgModule, ApplicationRef} from '@angular/core';
import {ApplicationRef, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {HttpModule} from '@angular/http';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {DemoApp, Home} from './demo-app/demo-app';
import {
MaterialModule,
OverlayContainer,
FullscreenOverlayContainer,
MaterialModule,
MdNativeDateModule,
MdSelectionModule,
OverlayContainer
} from '@angular/material';
import {DEMO_APP_ROUTES} from './demo-app/routes';
import {ProgressBarDemo} from './progress-bar/progress-bar-demo';
import {JazzDialog, ContentElementDialog, DialogDemo, IFrameDialog} from './dialog/dialog-demo';
import {ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog} from './dialog/dialog-demo';
import {RippleDemo} from './ripple/ripple-demo';
import {IconDemo} from './icon/icon-demo';
import {GesturesDemo} from './gestures/gestures-demo';
Expand All @@ -27,22 +28,23 @@ import {ListDemo} from './list/list-demo';
import {BaselineDemo} from './baseline/baseline-demo';
import {GridListDemo} from './grid-list/grid-list-demo';
import {LiveAnnouncerDemo} from './live-announcer/live-announcer-demo';
import {OverlayDemo, SpagettiPanel, RotiniPanel} from './overlay/overlay-demo';
import {OverlayDemo, RotiniPanel, SpagettiPanel} from './overlay/overlay-demo';
import {SlideToggleDemo} from './slide-toggle/slide-toggle-demo';
import {ToolbarDemo} from './toolbar/toolbar-demo';
import {ButtonDemo} from './button/button-demo';
import {MdCheckboxDemoNestedChecklist, CheckboxDemo} from './checkbox/checkbox-demo';
import {CheckboxDemo, MdCheckboxDemoNestedChecklist} from './checkbox/checkbox-demo';
import {SelectDemo} from './select/select-demo';
import {SliderDemo} from './slider/slider-demo';
import {SidenavDemo} from './sidenav/sidenav-demo';
import {SnackBarDemo} from './snack-bar/snack-bar-demo';
import {PortalDemo, ScienceJoke} from './portal/portal-demo';
import {MenuDemo} from './menu/menu-demo';
import {TabsDemo, SunnyTabContent, RainyTabContent, FoggyTabContent} from './tabs/tabs-demo';
import {FoggyTabContent, RainyTabContent, SunnyTabContent, TabsDemo} from './tabs/tabs-demo';
import {PlatformDemo} from './platform/platform-demo';
import {AutocompleteDemo} from './autocomplete/autocomplete-demo';
import {InputDemo} from './input/input-demo';
import {StyleDemo} from './style/style-demo';
import {DatepickerDemo} from './datepicker/datepicker-demo';


@NgModule({
Expand All @@ -54,6 +56,7 @@ import {StyleDemo} from './style/style-demo';
ReactiveFormsModule,
RouterModule.forRoot(DEMO_APP_ROUTES),
MaterialModule,
MdNativeDateModule,
MdSelectionModule,
],
declarations: [
Expand All @@ -64,6 +67,7 @@ import {StyleDemo} from './style/style-demo';
CardDemo,
ChipsDemo,
CheckboxDemo,
DatepickerDemo,
DemoApp,
DialogDemo,
GesturesDemo,
Expand Down
1 change: 1 addition & 0 deletions src/demo-app/demo-app/demo-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class DemoApp {
{name: 'Card', route: 'card'},
{name: 'Chips', route: 'chips'},
{name: 'Checkbox', route: 'checkbox'},
{name: 'Datepicker', route: 'datepicker'},
{name: 'Dialog', route: 'dialog'},
{name: 'Gestures', route: 'gestures'},
{name: 'Grid List', route: 'grid-list'},
Expand Down
2 changes: 2 additions & 0 deletions src/demo-app/demo-app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ import {PlatformDemo} from '../platform/platform-demo';
import {AutocompleteDemo} from '../autocomplete/autocomplete-demo';
import {InputDemo} from '../input/input-demo';
import {StyleDemo} from '../style/style-demo';
import {DatepickerDemo} from '../datepicker/datepicker-demo';

export const DEMO_APP_ROUTES: Routes = [
{path: '', component: Home},
{path: 'autocomplete', component: AutocompleteDemo},
{path: 'button', component: ButtonDemo},
{path: 'card', component: CardDemo},
{path: 'chips', component: ChipsDemo},
{path: 'datepicker', component: DatepickerDemo},
{path: 'radio', component: RadioDemo},
{path: 'select', component: SelectDemo},
{path: 'sidenav', component: SidenavDemo},
Expand Down
2 changes: 2 additions & 0 deletions src/lib/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ export {CompatibilityModule, NoConflictStyleCompatibilityMode} from './compatibi
// Common material module
export {MdCommonModule} from './common-behaviors/common-module';

// Datetime
export * from './datetime/index';

@NgModule({
imports: [
Expand Down
200 changes: 200 additions & 0 deletions src/lib/core/datetime/date-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/** Adapts type `D` to be usable as a date by cdk-based components that work with dates. */
export abstract class DateAdapter<D> {
/** The locale to use for all dates. */
protected locale: any;

/**
* Gets the year component of the given date.
* @param date The date to extract the year from.
* @returns The year component.
*/
abstract getYear(date: D): number;

/**
* Gets the month component of the given date.
* @param date The date to extract the month from.
* @returns The month component (0-indexed, 0 = January).
*/
abstract getMonth(date: D): number;

/**
* Gets the date of the month component of the given date.
* @param date The date to extract the date of the month from.
* @returns The month component (1-indexed, 1 = first of month).
*/
abstract getDate(date: D): number;

/**
* Gets the day of the week component of the given date.
* @param date The date to extract the day of the week from.
* @returns The month component (0-indexed, 0 = Sunday).
*/
abstract getDayOfWeek(date: D): number;

/**
* Gets a list of names for the months.
* @param style The naming style (e.g. long = 'January', short = 'Jan', narrow = 'J').
* @returns An ordered list of all month names, starting with January.
*/
abstract getMonthNames(style: 'long' | 'short' | 'narrow'): string[];

/**
* Gets a list of names for the dates of the month.
* @returns An ordered list of all date of the month names, starting with '1'.
*/
abstract getDateNames(): string[];

/**
* Gets a list of names for the days of the week.
* @param style The naming style (e.g. long = 'Sunday', short = 'Sun', narrow = 'S').
* @returns An ordered list of all weekday names, starting with Sunday.
*/
abstract getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[];

/**
* Gets the name for the year of the given date.
* @param date The date to get the year name for.
* @returns The name of the given year (e.g. '2017').
*/
abstract getYearName(date: D): string;

/**
* Gets the first day of the week.
* @returns The first day of the week (0-indexed, 0 = Sunday).
*/
abstract getFirstDayOfWeek(): number;

/**
* Gets the number of days in the month of the given date.
* @param date The date whose month should be checked.
* @returns The number of days in the month of the given date.
*/
abstract getNumDaysInMonth(date: D): number;

/**
* Clones the given date.
* @param date The date to clone
* @returns A new date equal to the given date.
*/
abstract clone(date: D): D;

/**
* Creates a date with the given year, month, and date. Does not allow over/under-flow of the
* month and date.
* @param year The full year of the date. (e.g. 89 means the year 89, not the year 1989).
* @param month The month of the date (0-indexed, 0 = January). Must be an integer 0 - 11.
* @param date The date of month of the date. Must be an integer 1 - length of the given month.
* @returns The new date, or null if invalid.
*/
abstract createDate(year: number, month: number, date: number): D;

/**
* Gets today's date.
* @returns Today's date.
*/
abstract today(): D;

/**
* Parses a date from a value.
* @param value The value to parse.
* @param parseFormat The expected format of the value being parsed
* (type is implementation-dependent).
* @returns The parsed date, or null if date could not be parsed.
*/
abstract parse(value: any, parseFormat: any): D | null;

/**
* Formats a date as a string.
* @param date The value to parse.
* @param displayFormat The format to use to display the date as a string.
* @returns The parsed date, or null if date could not be parsed.
*/
abstract format(date: D, displayFormat: any): string;

/**
* Adds the given number of years to the date. Years are counted as if flipping 12 pages on the
* calendar for each year and then finding the closest date in the new month. For example when
* adding 1 year to Feb 29, 2016, the resulting date will be Feb 28, 2017.
* @param date The date to add years to.
* @param years The number of years to add (may be negative).
* @returns A new date equal to the given one with the specified number of years added.
*/
abstract addCalendarYears(date: D, years: number): D;

/**
* Adds the given number of months to the date. Months are counted as if flipping a page on the
* calendar for each month and then finding the closest date in the new month. For example when
* adding 1 month to Jan 31, 2017, the resulting date will be Feb 28, 2017.
* @param date The date to add months to.
* @param months The number of months to add (may be negative).
* @returns A new date equal to the given one with the specified number of months added.
*/
abstract addCalendarMonths(date: D, months: number): D;

/**
* Adds the given number of days to the date. Days are counted as if moving one cell on the
* calendar for each day.
* @param date The date to add days to.
* @param days The number of days to add (may be negative).
* @returns A new date equal to the given one with the specified number of days added.
*/
abstract addCalendarDays(date: D, days: number): D;

/**
* Gets the RFC 3339 compatible date string (https://tools.ietf.org/html/rfc3339) for the given
* date.
* @param date The date to get the ISO date string for.
* @returns The ISO date string date string.
*/
abstract getISODateString(date: D): string;

/**
* Sets the locale used for all dates.
* @param locale The new locale.
*/
setLocale(locale: any) {
this.locale = locale;
}

/**
* Compares two dates.
* @param first The first date to compare.
* @param second The second date to compare.
* @returns 0 if the dates are equal, a number less than 0 if the first date is earlier,
* a number greater than 0 if the first date is later.
*/
compareDate(first: D, second: D): number {
return this.getYear(first) - this.getYear(second) ||
this.getMonth(first) - this.getMonth(second) ||
this.getDate(first) - this.getDate(second);
}

/**
* Checks if two dates are equal.
* @param first The first date to check.
* @param second The second date to check.
* @returns {boolean} Whether the two dates are equal.
* Null dates are considered equal to other null dates.
*/
sameDate(first: D | null, second: D | null): boolean {
return first && second ? !this.compareDate(first, second) : first == second;
}

/**
* Clamp the given date between min and max dates.
* @param date The date to clamp.
* @param min The minimum value to allow. If null or omitted no min is enforced.
* @param max The maximum value to allow. If null or omitted no max is enforced.
* @returns `min` if `date` is less than `min`, `max` if date is greater than `max`,
* otherwise `date`.
*/
clampDate(date: D, min?: D | null, max?: D | null): D {
if (min && this.compareDate(date, min) < 0) {
return min;
}
if (max && this.compareDate(date, max) > 0) {
return max;
}
return date;
}
}
Loading