Skip to content

Commit

Permalink
fix(focustrap): modal won't refocus last focused element
Browse files Browse the repository at this point in the history
on click anymore. Only datepicker input will.

Closes #2779
Closes #2798
  • Loading branch information
Benoit Charbonnier committed Oct 17, 2018
1 parent 1903185 commit ce7e626
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 28 deletions.
46 changes: 22 additions & 24 deletions src/datepicker/datepicker-input.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,37 @@
import {DOCUMENT} from '@angular/common';
import {
Directive,
Input,
ComponentFactoryResolver,
ComponentRef,
Directive,
ElementRef,
ViewContainerRef,
Renderer2,
ComponentFactoryResolver,
NgZone,
TemplateRef,
forwardRef,
EventEmitter,
Output,
forwardRef,
Inject,
Input,
NgZone,
OnChanges,
OnDestroy,
Output,
Renderer2,
SimpleChanges,
Inject
TemplateRef,
ViewContainerRef,
} from '@angular/core';
import {AbstractControl, ControlValueAccessor, Validator, NG_VALUE_ACCESSOR, NG_VALIDATORS} from '@angular/forms';
import {DOCUMENT} from '@angular/common';

import {NgbDate} from './ngb-date';
import {NgbDatepicker, NgbDatepickerNavigateEvent} from './datepicker';
import {DayTemplateContext} from './datepicker-day-template-context';
import {NgbDateParserFormatter} from './ngb-date-parser-formatter';
import {AbstractControl, ControlValueAccessor, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator} from '@angular/forms';
import {fromEvent, NEVER, race, Subject} from 'rxjs';
import {filter, takeUntil} from 'rxjs/operators';

import {positionElements, PlacementArray} from '../util/positioning';
import {ngbFocusTrap} from '../util/focus-trap';
import {Key} from '../util/key';
import {NgbDateStruct} from './ngb-date-struct';
import {PlacementArray, positionElements} from '../util/positioning';
import {NgbDateAdapter} from './adapters/ngb-date-adapter';
import {NgbCalendar} from './ngb-calendar';
import {NgbDatepicker, NgbDatepickerNavigateEvent} from './datepicker';
import {DayTemplateContext} from './datepicker-day-template-context';
import {NgbDatepickerService} from './datepicker-service';

import {Subject, fromEvent, race, NEVER} from 'rxjs';
import {filter, takeUntil} from 'rxjs/operators';
import {NgbCalendar} from './ngb-calendar';
import {NgbDate} from './ngb-date';
import {NgbDateParserFormatter} from './ngb-date-parser-formatter';
import {NgbDateStruct} from './ngb-date-struct';

const NGB_DATEPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
Expand Down Expand Up @@ -296,7 +294,7 @@ export class NgbInputDatepicker implements OnChanges,
}

// focus handling
ngbFocusTrap(this._cRef.location.nativeElement, this._closed$);
ngbFocusTrap(this._cRef.location.nativeElement, this._closed$, true);

this._cRef.instance.focus();

Expand Down
12 changes: 8 additions & 4 deletions src/util/focus-trap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ export function getFocusableBoundaryElements(element: HTMLElement): HTMLElement[
* @param element The element around which focus will be trapped inside
* @param stopFocusTrap$ The observable stream. When completed the focus trap will clean up listeners
* and free internal resources
* @param refocusOnClick Put the focus back to the last focused element whenever a click occurs on element (default to
* false)
*/
export const ngbFocusTrap = (element: HTMLElement, stopFocusTrap$: Observable<any>) => {
export const ngbFocusTrap = (element: HTMLElement, stopFocusTrap$: Observable<any>, refocusOnClick = false) => {
// last focused element
const lastFocusedElement$ =
fromEvent<FocusEvent>(element, 'focusin').pipe(takeUntil(stopFocusTrap$), map(e => e.target));
Expand All @@ -48,7 +50,9 @@ export const ngbFocusTrap = (element: HTMLElement, stopFocusTrap$: Observable<an
});

// inside click
fromEvent(element, 'click')
.pipe(takeUntil(stopFocusTrap$), withLatestFrom(lastFocusedElement$), map(arr => arr[1] as HTMLElement))
.subscribe(lastFocusedElement => lastFocusedElement.focus());
if (refocusOnClick) {
fromEvent(element, 'click')
.pipe(takeUntil(stopFocusTrap$), withLatestFrom(lastFocusedElement$), map(arr => arr[1] as HTMLElement))
.subscribe(lastFocusedElement => lastFocusedElement.focus());
}
};

0 comments on commit ce7e626

Please sign in to comment.