Skip to content

Commit

Permalink
feat(datepicker): merge datepicker branch into master (#4404)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalerba authored and kara committed May 12, 2017
1 parent 1ec88e0 commit 123d7ec
Show file tree
Hide file tree
Showing 47 changed files with 4,562 additions and 13 deletions.
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 @@ -30,6 +30,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 @@ -103,6 +103,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

0 comments on commit 123d7ec

Please sign in to comment.