nycJSorg/angular-presentation

View on GitHub
libs/slides/src/lib/shortcuts/shortcuts.directive.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { Directive, HostListener, Optional } from '@angular/core';
import { FullScreenModeService } from '../full-screen-mode';
import { SlidesDeckComponent } from '../deck/deck.component';

@Directive({
  selector: '[slideShortcuts]'
})
export class ShortcutsDirective {
  constructor(
    @Optional() private deck: SlidesDeckComponent,
    private fullScreenService: FullScreenModeService
  ) {}

  @HostListener('window:keydown.ArrowRight', ['$event.target'])
  @HostListener('window:keydown.PageDown', ['$event.target'])
  next(target) {
    if (this.canNavigate(target) && this.deck.canGoNext()) {
      this.deck.nextSlide();
    }
  }

  @HostListener('window:keydown.ArrowLeft', ['$event.target'])
  @HostListener('window:keydown.PageUp', ['$event.target'])
  previous(target) {
    if (this.canNavigate(target) && this.deck.canGoPrevious()) {
      this.deck.previousSlide();
    }
  }

  @HostListener('window:keydown.alt.enter', ['$event'])
  fullScreenModeToggle(e) {
    // prevent page reload
    e.preventDefault();

    this.fullScreenService.toggleFullScreen();
  }

  private canNavigate(target: HTMLElement) {
    return target === document.body || this.isFromContext(target);
  }

  /**
   * Limit keyboard shortcut events to scoped containers
   * to prevent slide navigation when using keyboard arrows to
   * navigate an editable field like code editor.
   * Add '.shortcuts-context' to any component or container containig
   * focusable elements used for slide navigation.
   */
  private isFromContext(target: HTMLElement) {
    let parent = target;

    while (parent) {
      if (parent.classList.contains('shortcuts-context')) {
        return true;
      }
      parent = parent.parentElement;
    }

    return false;
  }
}