diff --git a/e2e-app/src/app/datepicker/focus/datepicker-focus.e2e-spec.ts b/e2e-app/src/app/datepicker/focus/datepicker-focus.e2e-spec.ts index dd32d45074..358a4717d4 100644 --- a/e2e-app/src/app/datepicker/focus/datepicker-focus.e2e-spec.ts +++ b/e2e-app/src/app/datepicker/focus/datepicker-focus.e2e-spec.ts @@ -59,34 +59,26 @@ describe('Datepicker', () => { await expectFocused(page.getToggle(), `Toggle element should stay focused after datepicker is closed`); }); - it(`should be closed on Escape and focus nothing`, async() => { + it(`should be closed on Escape and re-focus toggle element`, async() => { await page.openDatepicker(); // close await sendKey(Key.ESCAPE); expect(await page.getDatepicker().isPresent()).toBeFalsy(`Datepicker should not be present on the page`); - // check nothing is focused - await expectFocused($('body'), `Nothing should be focused after datepicker is closed`); - - // tab should focus toggling element - await sendKey(Key.TAB); - await expectFocused(page.getToggle(), `Toggle element should become focused on Tab press`); + // check toggle is focused + await expectFocused(page.getToggle(), `Toggle element become re-focused after datepicker is closed`); }); - it(`should be closed on date selection and focus nothing`, async() => { + it(`should be closed on date selection and re-focus toggle element`, async() => { await page.openDatepicker(); // close await page.getToday().click(); expect(await page.getDatepicker().isPresent()).toBeFalsy(`Datepicker should not be present on the page`); - // check nothing is focused - await expectFocused($('body'), `Nothing should be focused after datepicker is closed`); - - // tab should focus toggling element - await sendKey(Key.TAB); - await expectFocused(page.getToggle(), `Toggle element should become focused on Tab press`); + // check toggle is focused + await expectFocused(page.getToggle(), `Toggle element become re-focused after datepicker is closed`); }); it(`should trap focus inside opened popup (Tab)`, async() => { @@ -188,6 +180,22 @@ describe('Datepicker', () => { await expectFocused(page.getPrevMonthArrow(), `Previous Month arrow should be focused`); }); + it(`should be closed on Escape from input and keep focus`, async() => { + await page.openDatepicker(); + const datepickerInput = page.getDatepickerInput(); + + // focus input + await datepickerInput.click(); + await expectFocused(datepickerInput, `Datepicker input should be focused`); + + // close + await sendKey(Key.ESCAPE); + expect(await page.getDatepicker().isPresent()).toBeFalsy(`Datepicker should not be present on the page`); + + // check input is still focused + await expectFocused(page.getDatepickerInput(), `Input element should stay focused after datepicker is closed`); + }); + describe('Keyboard', () => { it(`should handle focus correctly when months are changed with keyboard`, async() => { diff --git a/src/datepicker/datepicker-input.ts b/src/datepicker/datepicker-input.ts index c7c25616ea..08026a6007 100644 --- a/src/datepicker/datepicker-input.ts +++ b/src/datepicker/datepicker-input.ts @@ -56,6 +56,7 @@ const NGB_DATEPICKER_VALIDATOR = { host: { '(input)': 'manualDateChange($event.target.value)', '(change)': 'manualDateChange($event.target.value, true)', + '(focus)': 'onFocus()', '(blur)': 'onBlur()', '[disabled]': 'disabled' }, @@ -65,6 +66,7 @@ export class NgbInputDatepicker implements OnChanges, OnDestroy, ControlValueAccessor, Validator { private _cRef: ComponentRef = null; private _disabled = false; + private _elWithFocus = null; private _model: NgbDate; private _inputValue: string; private _zoneSubscription: any; @@ -345,6 +347,7 @@ export class NgbInputDatepicker implements OnChanges, } // focus handling + this._elWithFocus = this._document.activeElement; ngbFocusTrap(this._cRef.location.nativeElement, this.closed, true); this._cRef.instance.focus(); @@ -363,6 +366,10 @@ export class NgbInputDatepicker implements OnChanges, this._cRef = null; this.closed.emit(); this._changeDetector.markForCheck(); + + // restore focus + const elementToFocus = this._elWithFocus && this._elWithFocus['focus'] ? this._elWithFocus : this._document.body; + elementToFocus.focus(); } } @@ -393,6 +400,8 @@ export class NgbInputDatepicker implements OnChanges, onBlur() { this._onTouched(); } + onFocus() { this._elWithFocus = this._elRef.nativeElement; } + ngOnChanges(changes: SimpleChanges) { if (changes['minDate'] || changes['maxDate']) { this._validatorChange();