Project

General

Profile

1
import {Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core';
2
import {fromEvent, Subscriber} from 'rxjs';
3
import {delay, tap} from 'rxjs/operators';
4

    
5
@Directive({
6
  selector: '[click-outside-or-esc]'
7
})
8

    
9
export class ClickOutsideOrEsc implements OnInit, OnDestroy {
10
  private listening: boolean;
11
  private subscriptions: any[] = [];
12
  @Input()
13
  public targetId = null;
14
  @Input()
15
  public escClose = true;
16
  @Input()
17
  public clickClose = true;
18
  @Output('clickOutside') clickOutside: EventEmitter<Object>;
19

    
20
  constructor(private _elRef: ElementRef) {
21
    this.listening = false;
22
    this.clickOutside = new EventEmitter();
23
  }
24

    
25
  ngOnInit() {
26
    if(typeof document !== 'undefined') {
27
      this.subscriptions.push(fromEvent(document, 'click').pipe(
28
        delay(1),
29
        tap(() => {
30
          this.listening = true;
31
        })).subscribe((event: MouseEvent) => {
32
          this.onGlobalClick(event);
33
        }));
34
      this.subscriptions.push(fromEvent(document, 'click').pipe(
35
        delay(1),
36
        tap(() => {
37
          this.listening = true;
38
        })).subscribe((event: KeyboardEvent) => {
39
          if (event.keyCode === 27 && this.escClose) {
40
            this.clickOutside.emit({
41
              target: (event.target || null),
42
              value: true
43
            });
44
          }
45
        }));
46
    }
47
  }
48

    
49
  ngOnDestroy() {
50
    if (this.subscriptions) {
51
      this.subscriptions.forEach((subscription: Subscriber<any>) => {
52
        subscription.unsubscribe();
53
      });
54
    }
55
    this.subscriptions = [];
56
  }
57

    
58
  onGlobalClick(event: MouseEvent) {
59
    if (event instanceof MouseEvent && this.listening === true) {
60
      let element: HTMLElement = <HTMLElement>event.target;
61
      while (element) {
62
        if(element.id === this.targetId) {
63
          this.clickOutside.emit({
64
            target: (event.target || null),
65
            value: false
66
          });
67
          return;
68
        }
69
        element = element.parentElement;
70
      }
71
      if(this.clickClose) {
72
        this.clickOutside.emit({
73
          target: (event.target || null),
74
          value: true
75
        });
76
      }
77
    }
78
  }
79
}
(1-1/3)