Skip to content

Commit

Permalink
fix(datepicker): keyboard fixes (enter matches click behavior & corre… (
Browse files Browse the repository at this point in the history
#7370)

* fix(datepicker): keyboard fixes (enter matches click behavior & correct up and down arrow behavior in year mode).

* fix tests
  • Loading branch information
mmalerba authored Dec 5, 2017
1 parent e7b412a commit 0b2757c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 20 deletions.
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();
// 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

0 comments on commit 0b2757c

Please sign in to comment.