in src/cdk-experimental/popover-edit/table-directives.ts [86:153]
private _listenForTableEvents(): void {
const element = this.elementRef.nativeElement;
const toClosest = (selector: string) =>
map((event: UIEvent) => closest(event.target, selector));
this.ngZone.runOutsideAngular(() => {
// Track mouse movement over the table to hide/show hover content.
fromEvent<MouseEvent>(element, 'mouseover')
.pipe(toClosest(ROW_SELECTOR), takeUntil(this.destroyed))
.subscribe(this.editEventDispatcher.hovering);
fromEvent<MouseEvent>(element, 'mouseleave')
.pipe(mapTo(null), takeUntil(this.destroyed))
.subscribe(this.editEventDispatcher.hovering);
fromEvent<MouseEvent>(element, 'mousemove')
.pipe(
throttleTime(MOUSE_MOVE_THROTTLE_TIME_MS),
toClosest(ROW_SELECTOR),
takeUntil(this.destroyed),
)
.subscribe(this.editEventDispatcher.mouseMove);
// Track focus within the table to hide/show/make focusable hover content.
fromEventPattern<FocusEvent>(
handler => element.addEventListener('focus', handler, true),
handler => element.removeEventListener('focus', handler, true),
)
.pipe(toClosest(ROW_SELECTOR), share(), takeUntil(this.destroyed))
.subscribe(this.editEventDispatcher.focused);
merge(
fromEventPattern<FocusEvent>(
handler => element.addEventListener('blur', handler, true),
handler => element.removeEventListener('blur', handler, true),
),
fromEvent<KeyboardEvent>(element, 'keydown').pipe(filter(event => event.key === 'Escape')),
)
.pipe(mapTo(null), share(), takeUntil(this.destroyed))
.subscribe(this.editEventDispatcher.focused);
// Keep track of rows within the table. This is used to know which rows with hover content
// are first or last in the table. They are kept focusable in case focus enters from above
// or below the table.
this.ngZone.onStable
.pipe(
// Optimization: ignore dom changes while focus is within the table as we already
// ensure that rows above and below the focused/active row are tabbable.
withLatestFrom(this.editEventDispatcher.editingOrFocused),
filter(([_, activeRow]) => activeRow == null),
map(() => element.querySelectorAll(ROW_SELECTOR)),
share(),
takeUntil(this.destroyed),
)
.subscribe(this.editEventDispatcher.allRows);
fromEvent<KeyboardEvent>(element, 'keydown')
.pipe(
filter(event => event.key === 'Enter'),
toClosest(CELL_SELECTOR),
takeUntil(this.destroyed),
)
.subscribe(this.editEventDispatcher.editing);
// Keydown must be used here or else key autorepeat does not work properly on some platforms.
fromEvent<KeyboardEvent>(element, 'keydown')
.pipe(takeUntil(this.destroyed))
.subscribe(this.focusDispatcher.keyObserver);
});
}