From 9ba99816d722e8e642c95401e950de5ef3cf5538 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 11 Dec 2017 22:15:53 +0100 Subject: [PATCH] refactor(datepicker): use common overlay keyboard handling Switches the datepicker to use the `OverlayKeyboardDispatcher`, rather than managing the keyboard logic itself. This simplifies things and handles the cases where the popup won't close if it lost focus. --- src/lib/datepicker/datepicker.spec.ts | 28 +++++++-------------------- src/lib/datepicker/datepicker.ts | 21 ++++++-------------- 2 files changed, 13 insertions(+), 36 deletions(-) diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index 041b18da34c2..5a9e3398cdad 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -1,12 +1,6 @@ import {ENTER, ESCAPE, RIGHT_ARROW} from '@angular/cdk/keycodes'; import {OverlayContainer, Overlay, ScrollDispatcher} from '@angular/cdk/overlay'; -import { - createKeyboardEvent, - dispatchEvent, - dispatchFakeEvent, - dispatchKeyboardEvent, - dispatchMouseEvent, -} from '@angular/cdk/testing'; +import {dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent} from '@angular/cdk/testing'; import {Component, ViewChild} from '@angular/core'; import {fakeAsync, flush, ComponentFixture, inject, TestBed} from '@angular/core/testing'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; @@ -157,26 +151,18 @@ describe('MatDatepicker', () => { expect(parseInt(getComputedStyle(popup).height as string)).toBe(0); }); - it('should close the popup when pressing ESCAPE', () => { + it('should close the popup when pressing ESCAPE', fakeAsync(() => { testComponent.datepicker.open(); fixture.detectChanges(); - let content = document.querySelector('.cdk-overlay-pane mat-datepicker-content')!; - expect(content).toBeTruthy('Expected datepicker to be open.'); - - const keyboardEvent = createKeyboardEvent('keydown', ESCAPE); - const stopPropagationSpy = spyOn(keyboardEvent, 'stopPropagation').and.callThrough(); + expect(testComponent.datepicker.opened).toBe(true, 'Expected datepicker to be open.'); - dispatchEvent(content, keyboardEvent); + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); fixture.detectChanges(); + flush(); - content = document.querySelector('.cdk-overlay-pane mat-datepicker-content')!; - - expect(content).toBeFalsy('Expected datepicker to be closed.'); - expect(stopPropagationSpy).toHaveBeenCalled(); - expect(keyboardEvent.defaultPrevented) - .toBe(true, 'Expected default ESCAPE action to be prevented.'); - }); + expect(testComponent.datepicker.opened).toBe(false, 'Expected datepicker to be closed.'); + })); it('close should close dialog', fakeAsync(() => { testComponent.touch = true; diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 90a6484a243b..bf98225b2177 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -19,6 +19,7 @@ import { } from '@angular/cdk/overlay'; import {ComponentPortal} from '@angular/cdk/portal'; import {take} from 'rxjs/operators/take'; +import {filter} from 'rxjs/operators/filter'; import { AfterContentInit, ChangeDetectionStrategy, @@ -83,7 +84,6 @@ export const MAT_DATEPICKER_SCROLL_STRATEGY_PROVIDER = { host: { 'class': 'mat-datepicker-content', '[class.mat-datepicker-content-touch]': 'datepicker.touchUi', - '(keydown)': '_handleKeydown($event)', }, exportAs: 'matDatepickerContent', encapsulation: ViewEncapsulation.None, @@ -98,18 +98,6 @@ export class MatDatepickerContent implements AfterContentInit { ngAfterContentInit() { this._calendar._focusActiveCell(); } - - /** - * Handles keydown event on datepicker content. - * @param event The event. - */ - _handleKeydown(event: KeyboardEvent): void { - if (event.keyCode === ESCAPE) { - this.datepicker.close(); - event.preventDefault(); - event.stopPropagation(); - } - } } @@ -382,8 +370,11 @@ export class MatDatepicker implements OnDestroy { this._popupRef = this._overlay.create(overlayConfig); - merge(this._popupRef.backdropClick(), this._popupRef.detachments()) - .subscribe(() => this.close()); + merge( + this._popupRef.backdropClick(), + this._popupRef.detachments(), + this._popupRef.keydownEvents().pipe(filter(event => event.keyCode === ESCAPE)) + ).subscribe(() => this.close()); } /** Create the popup PositionStrategy. */