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 5 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
112 changes: 91 additions & 21 deletions src/lib/core/datetime/native-date-adapter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import {NativeDateAdapter} from './native-date-adapter';
import {Platform} from '../platform/index';


const SUPPORTS_INTL = typeof Intl != 'undefined';


// When constructing a Date, the month is zero-based. This can be confusing, since people are
Expand All @@ -9,9 +13,11 @@ const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SE

describe('NativeDateAdapter', () => {
let adapter;
let platform;

beforeEach(() => {
adapter = new NativeDateAdapter();
platform = new Platform();
});

it('should get year', () => {
Expand Down Expand Up @@ -44,16 +50,30 @@ describe('NativeDateAdapter', () => {
});

it('should get narrow month names', () => {
expect(adapter.getMonthNames('narrow')).toEqual([
'J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'
]);
// Edge & IE use same value for short and narrow.
if (platform.EDGE || platform.TRIDENT) {
expect(adapter.getMonthNames('narrow')).toEqual([
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
]);
} else {
expect(adapter.getMonthNames('narrow')).toEqual([
'J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'
]);
}
});

it('should get month names in a different locale', () => {
adapter.setLocale('ja-JP');
expect(adapter.getMonthNames('long')).toEqual([
'1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'
]);
if (SUPPORTS_INTL) {
expect(adapter.getMonthNames('long')).toEqual([
'1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'
]);
} else {
expect(adapter.getMonthNames('long')).toEqual([
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December'
]);
}
});

it('should get date names', () => {
Expand All @@ -65,11 +85,18 @@ describe('NativeDateAdapter', () => {

it('should get date names in a different locale', () => {
adapter.setLocale('ja-JP');
expect(adapter.getDateNames()).toEqual([
'1日', '2日', '3日', '4日', '5日', '6日', '7日', '8日', '9日', '10日', '11日', '12日',
'13日', '14日', '15日', '16日', '17日', '18日', '19日', '20日', '21日', '22日', '23日', '24日',
'25日', '26日', '27日', '28日', '29日', '30日', '31日'
]);
if (SUPPORTS_INTL) {
expect(adapter.getDateNames()).toEqual([
'1日', '2日', '3日', '4日', '5日', '6日', '7日', '8日', '9日', '10日', '11日', '12日',
'13日', '14日', '15日', '16日', '17日', '18日', '19日', '20日', '21日', '22日', '23日', '24日',
'25日', '26日', '27日', '28日', '29日', '30日', '31日'
]);
} else {
expect(adapter.getDateNames()).toEqual([
'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17',
'18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31'
]);
}
});

it('should get long day of week names', () => {
Expand All @@ -85,14 +112,29 @@ describe('NativeDateAdapter', () => {
});

it('should get narrow day of week names', () => {
expect(adapter.getDayOfWeekNames('narrow')).toEqual(['S', 'M', 'T', 'W', 'T', 'F', 'S']);
// Edge & IE use two-letter narrow days.
if (platform.EDGE || platform.TRIDENT) {
expect(adapter.getDayOfWeekNames('narrow')).toEqual([
'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'
]);
} else {
expect(adapter.getDayOfWeekNames('narrow')).toEqual([
'S', 'M', 'T', 'W', 'T', 'F', 'S'
]);
}
});

it('should get day of week names in a different locale', () => {
adapter.setLocale('ja-JP');
expect(adapter.getDayOfWeekNames('long')).toEqual([
'日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'
]);
if (SUPPORTS_INTL) {
expect(adapter.getDayOfWeekNames('long')).toEqual([
'日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'
]);
} else {
expect(adapter.getDayOfWeekNames('long')).toEqual([
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
]);
}
});

it('should get year name', () => {
Expand All @@ -101,7 +143,11 @@ describe('NativeDateAdapter', () => {

it('should get year name in a different locale', () => {
adapter.setLocale('ja-JP');
expect(adapter.getYearName(new Date(2017, JAN, 1))).toBe('2017年');
if (SUPPORTS_INTL) {
expect(adapter.getYearName(new Date(2017, JAN, 1))).toBe('2017年');
} else {
expect(adapter.getYearName(new Date(2017, JAN, 1))).toBe('2017');
}
});

it('should get first day of week', () => {
Expand Down Expand Up @@ -136,7 +182,7 @@ describe('NativeDateAdapter', () => {
});

it('should parse string', () => {
expect(adapter.parse('1/1/17')).toEqual(new Date(2017, JAN, 1));
expect(adapter.parse('1/1/2017')).toEqual(new Date(2017, JAN, 1));
});

it('should parse number', () => {
Expand All @@ -155,17 +201,41 @@ describe('NativeDateAdapter', () => {
});

it('should format', () => {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('1/1/2017');
if (SUPPORTS_INTL) {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('1/1/2017');
} else {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('Sun Jan 01 2017');
}
});

it('should format with custom format', () => {
expect(adapter.format(new Date(2017, JAN, 1), {year: 'numeric', month: 'long', day: 'numeric'}))
.toEqual('January 1, 2017');
if (SUPPORTS_INTL) {
expect(adapter.format(new Date(2017, JAN, 1), {
year: 'numeric',
month: 'long',
day: 'numeric'
})).toEqual('January 1, 2017');
} else {
expect(adapter.format(new Date(2017, JAN, 1), {
year: 'numeric',
month: 'long',
day: 'numeric'
})).toEqual('Sun Jan 01 2017');
}
});

it('should format with a different locale', () => {
adapter.setLocale('ja-JP');
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('2017/1/1');
if (SUPPORTS_INTL) {
// Edge & IE use a different format in Japanese.
if (platform.EDGE || platform.TRIDENT) {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('2017年1月1日');
} else {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('2017/1/1');
}
} else {
expect(adapter.format(new Date(2017, JAN, 1))).toEqual('Sun Jan 01 2017');
}
});

it('should add years', () => {
Expand Down
23 changes: 17 additions & 6 deletions src/lib/core/datetime/native-date-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,31 @@ export class NativeDateAdapter extends DateAdapter<Date> {
getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
if (SUPPORTS_INTL_API) {
let dtf = new Intl.DateTimeFormat(this.locale, {month: style});
return range(12, i => dtf.format(new Date(2017, i, 1)));
return range(12, i => this._stripDirectionCharacters(dtf.format(new Date(2017, i, 1))));
}
return DEFAULT_MONTH_NAMES[style];
}

getDateNames(): string[] {
if (SUPPORTS_INTL_API) {
let dtf = new Intl.DateTimeFormat(this.locale, {day: 'numeric'});
return range(31, i => dtf.format(new Date(2017, 0, i + 1)));
return range(31, i => this._stripDirectionCharacters(dtf.format(new Date(2017, 0, i + 1))));
}
return DEFAULT_DATE_NAMES;
}

getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
if (SUPPORTS_INTL_API) {
let dtf = new Intl.DateTimeFormat(this.locale, {weekday: style});
return range(7, i => dtf.format(new Date(2017, 0, i + 1)));
return range(7, i => this._stripDirectionCharacters(dtf.format(new Date(2017, 0, i + 1))));
}
return DEFAULT_DAY_OF_WEEK_NAMES[style];
}

getYearName(date: Date): string {
if (SUPPORTS_INTL_API) {
let dtf = new Intl.DateTimeFormat(this.locale, {year: 'numeric'});
return dtf.format(date);
return this._stripDirectionCharacters(dtf.format(date));
}
return String(this.getYear(date));
}
Expand Down Expand Up @@ -131,9 +131,9 @@ export class NativeDateAdapter extends DateAdapter<Date> {
format(date: Date, displayFormat: Object): string {
if (SUPPORTS_INTL_API) {
let dtf = new Intl.DateTimeFormat(this.locale, displayFormat);
return dtf.format(date);
return this._stripDirectionCharacters(dtf.format(date));
}
return date.toDateString();
return this._stripDirectionCharacters(date.toDateString());
}

addCalendarYears(date: Date, years: number): Date {
Expand Down Expand Up @@ -188,4 +188,15 @@ export class NativeDateAdapter extends DateAdapter<Date> {
private _2digit(n: number) {
return ('00' + n).slice(-2);
}

/**
* Strip out unicode LTR and RTL characters. Edge and IE insert these into formatted dates while
* other browsers do not. We remove them to make output consistent and because they interfere with
* date parsing.
* @param s The string to strip direction characters from.
* @returns {string} The stripped string.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Omit return type from comment

*/
private _stripDirectionCharacters(s: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_stripDirectionalityCharacters? (to match our pending terminology)

return s.replace(/[\u200e\u200f]/g, '');
}
}
8 changes: 4 additions & 4 deletions src/lib/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
Input,
OnDestroy,
Optional,
Renderer
Renderer2
} from '@angular/core';
import {MdDatepicker} from './datepicker';
import {
Expand Down Expand Up @@ -91,7 +91,7 @@ export class MdDatepickerInput<D> implements AfterContentInit, ControlValueAcces
set value(value: D) {
let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
let oldDate = this.value;
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value',
this._renderer.setProperty(this._elementRef.nativeElement, 'value',
date ? this._dateAdapter.format(date, this._dateFormats.display.dateInput) : '');
if (!this._dateAdapter.sameDate(oldDate, date)) {
this._valueChange.emit(date);
Expand Down Expand Up @@ -153,7 +153,7 @@ export class MdDatepickerInput<D> implements AfterContentInit, ControlValueAcces

constructor(
private _elementRef: ElementRef,
private _renderer: Renderer,
private _renderer: Renderer2,
@Optional() private _dateAdapter: DateAdapter<D>,
@Optional() @Inject(MD_DATE_FORMATS) private _dateFormats: MdDateFormats,
@Optional() private _mdInputContainer: MdInputContainer) {
Expand Down Expand Up @@ -214,7 +214,7 @@ export class MdDatepickerInput<D> implements AfterContentInit, ControlValueAcces

// Implemented as part of ControlValueAccessor
setDisabledState(disabled: boolean): void {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'disabled', disabled);
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', disabled);
}

_onKeydown(event: KeyboardEvent) {
Expand Down