Skip to content

fix(datepicker): keyboard fixes (enter matches click behavior & corre… #7370

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

Merged
merged 2 commits into from
Dec 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 8 additions & 7 deletions src/lib/datepicker/calendar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import {
JUL,
JUN,
MAR,
MAY,
MatNativeDateModule,
MAY,
NOV,
OCT,
SEP,
} from '@angular/material/core';
import {By} from '@angular/platform-browser';
Expand Down Expand Up @@ -341,46 +342,46 @@ describe('MatCalendar', () => {
dispatchKeyboardEvent(calendarBodyEl, 'keydown', UP_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2016, AUG, 31));
expect(calendarInstance._activeDate).toEqual(new Date(2016, SEP, 30));

calendarInstance._activeDate = new Date(2017, JUL, 1);
fixture.detectChanges();

dispatchKeyboardEvent(calendarBodyEl, 'keydown', UP_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2016, JUL, 1));
expect(calendarInstance._activeDate).toEqual(new Date(2017, MAR, 1));

calendarInstance._activeDate = new Date(2017, DEC, 10);
fixture.detectChanges();

dispatchKeyboardEvent(calendarBodyEl, 'keydown', UP_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2017, MAY, 10));
expect(calendarInstance._activeDate).toEqual(new Date(2017, AUG, 10));
});

it('should go down a row on down arrow press', () => {
dispatchKeyboardEvent(calendarBodyEl, 'keydown', DOWN_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2017, AUG, 31));
expect(calendarInstance._activeDate).toEqual(new Date(2017, MAY, 31));

calendarInstance._activeDate = new Date(2017, JUN, 1);
fixture.detectChanges();

dispatchKeyboardEvent(calendarBodyEl, 'keydown', DOWN_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2018, JUN, 1));
expect(calendarInstance._activeDate).toEqual(new Date(2017, OCT, 1));

calendarInstance._activeDate = new Date(2017, SEP, 30);
fixture.detectChanges();

dispatchKeyboardEvent(calendarBodyEl, 'keydown', DOWN_ARROW);
fixture.detectChanges();

expect(calendarInstance._activeDate).toEqual(new Date(2018, FEB, 28));
expect(calendarInstance._activeDate).toEqual(new Date(2018, JAN, 30));
});

it('should go to first month of the year on home press', () => {
Expand Down
15 changes: 5 additions & 10 deletions src/lib/datepicker/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
case ENTER:
if (this._dateFilterForViews(this._activeDate)) {
this._dateSelected(this._activeDate);
this._userSelected();
Copy link
Member

Choose a reason for hiding this comment

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

Add test?

// Prevent unexpected default actions such as form submission.
event.preventDefault();
}
Expand Down Expand Up @@ -375,23 +376,17 @@ export class MatCalendar<D> implements AfterContentInit, OnDestroy, OnChanges {
* calendar table.
*/
private _prevMonthInSameCol(date: D): D {
// Determine how many months to jump forward given that there are 2 empty slots at the beginning
// of each year.
let increment = this._dateAdapter.getMonth(date) <= 4 ? -5 :
(this._dateAdapter.getMonth(date) >= 7 ? -7 : -12);
return this._dateAdapter.addCalendarMonths(date, increment);
// Decrement by 4 since there are 4 months per row.
return this._dateAdapter.addCalendarMonths(date, -4);
}

/**
* Determine the date for the month that comes after the given month in the same column in the
* calendar table.
*/
private _nextMonthInSameCol(date: D): D {
// Determine how many months to jump forward given that there are 2 empty slots at the beginning
// of each year.
let increment = this._dateAdapter.getMonth(date) <= 4 ? 7 :
(this._dateAdapter.getMonth(date) >= 7 ? 5 : 12);
return this._dateAdapter.addCalendarMonths(date, increment);
// Increment by 4 since there are 4 months per row.
return this._dateAdapter.addCalendarMonths(date, 4);
}

/**
Expand Down
52 changes: 49 additions & 3 deletions src/lib/datepicker/datepicker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {ESCAPE} from '@angular/cdk/keycodes';
import {ENTER, ESCAPE, RIGHT_ARROW} from '@angular/cdk/keycodes';
import {OverlayContainer} from '@angular/cdk/overlay';
import {
createKeyboardEvent,
dispatchEvent,
dispatchFakeEvent,
dispatchKeyboardEvent,
dispatchMouseEvent,
} from '@angular/cdk/testing';
import {Component, ViewChild} from '@angular/core';
Expand Down Expand Up @@ -203,7 +204,7 @@ describe('MatDatepicker', () => {
});
}));

it('setting selected should update input and close calendar', async(() => {
it('setting selected via click should update input and close calendar', async(() => {
testComponent.touch = true;
fixture.detectChanges();

Expand All @@ -223,8 +224,31 @@ describe('MatDatepicker', () => {
});
}));

it('setting selected via enter press should update input and close calendar', () => {
testComponent.touch = true;
fixture.detectChanges();

testComponent.datepicker.open();
fixture.detectChanges();

expect(document.querySelector('mat-dialog-container')).not.toBeNull();
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1));

let calendarBodyEl = document.querySelector('.mat-calendar-content') as HTMLElement;

dispatchKeyboardEvent(calendarBodyEl, 'keydown', RIGHT_ARROW);
fixture.detectChanges();
dispatchKeyboardEvent(calendarBodyEl, 'keydown', ENTER);
fixture.detectChanges();

fixture.whenStable().then(() => {
expect(document.querySelector('mat-dialog-container')).toBeNull();
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
});
});

it('clicking the currently selected date should close the calendar ' +
'without firing selectedChanged', () => {
'without firing selectedChanged', () => {
const selectedChangedSpy =
spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough();

Expand All @@ -246,6 +270,28 @@ describe('MatDatepicker', () => {
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2));
});

it('pressing enter on the currently selected date should close the calendar without ' +
'firing selectedChanged', () => {
const selectedChangedSpy =
spyOn(testComponent.datepicker.selectedChanged, 'emit').and.callThrough();

testComponent.datepicker.open();
fixture.detectChanges();

let calendarBodyEl = document.querySelector('.mat-calendar-content') as HTMLElement;
expect(calendarBodyEl).not.toBeNull();
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1));

dispatchKeyboardEvent(calendarBodyEl, 'keydown', ENTER);
fixture.detectChanges();

fixture.whenStable().then(() => {
expect(selectedChangedSpy.calls.count()).toEqual(0);
expect(document.querySelector('mat-dialog-container')).toBeNull();
expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1));
});
});

it('startAt should fallback to input value', () => {
expect(testComponent.datepicker.startAt).toEqual(new Date(2020, JAN, 1));
});
Expand Down