aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/shared-main/misc/list-overflow.component.ts
blob: 7e4e1b1d1b1d73332402ec01cc4484d4d8cac463 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import { lowerFirst, uniqueId } from 'lodash-es'
import { take } from 'rxjs/operators'
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef,
  HostListener,
  Input,
  QueryList,
  TemplateRef,
  ViewChild,
  ViewChildren
} from '@angular/core'
import { ScreenService } from '@app/core'
import { NgbDropdown, NgbModal } from '@ng-bootstrap/ng-bootstrap'
import * as debug from 'debug'

const debugLogger = debug('peertube:main:ListOverflowItem')

export interface ListOverflowItem {
  label: string
  routerLink: string | any[]
}

@Component({
  selector: 'my-list-overflow',
  templateUrl: './list-overflow.component.html',
  styleUrls: [ './list-overflow.component.scss' ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListOverflowComponent<T extends ListOverflowItem> implements AfterViewInit {
  @Input() items: T[]
  @Input() itemTemplate: TemplateRef<{item: T}>

  @ViewChild('modal', { static: true }) modal: ElementRef
  @ViewChild('itemsParent', { static: true }) parent: ElementRef<HTMLDivElement>
  @ViewChildren('itemsRendered') itemsRendered: QueryList<ElementRef>

  showItemsUntilIndexExcluded: number
  active = false
  isInMobileView = false

  private openedOnHover = false

  constructor (
    private cdr: ChangeDetectorRef,
    private modalService: NgbModal,
    private screenService: ScreenService
  ) {}

  ngAfterViewInit () {
    setTimeout(() => this.onWindowResize(), 0)
  }

  isMenuDisplayed () {
    return !!this.showItemsUntilIndexExcluded
  }

  @HostListener('window:resize')
  onWindowResize () {
    this.isInMobileView = !!this.screenService.isInMobileView()

    const parentWidth = this.parent.nativeElement.getBoundingClientRect().width
    let showItemsUntilIndexExcluded: number
    let accWidth = 0

    debugLogger('Parent width is %d', parentWidth)

    for (const [ index, el ] of this.itemsRendered.toArray().entries()) {
      accWidth += el.nativeElement.getBoundingClientRect().width
      if (showItemsUntilIndexExcluded === undefined) {
        showItemsUntilIndexExcluded = (parentWidth < accWidth) ? index : undefined
      }

      const e = document.getElementById(this.getId(index))
      const shouldBeVisible = showItemsUntilIndexExcluded ? index < showItemsUntilIndexExcluded : true
      e.style.visibility = shouldBeVisible ? 'inherit' : 'hidden'
    }

    debugLogger('Accumulated children width is %d so exclude index is %d', accWidth, showItemsUntilIndexExcluded)

    this.showItemsUntilIndexExcluded = showItemsUntilIndexExcluded
    this.cdr.markForCheck()
  }

  openDropdownOnHover (dropdown: NgbDropdown) {
    this.openedOnHover = true
    dropdown.open()

    // Menu was closed
    dropdown.openChange
            .pipe(take(1))
            .subscribe(() => this.openedOnHover = false)
  }

  dropdownAnchorClicked (dropdown: NgbDropdown) {
    if (this.openedOnHover) {
      this.openedOnHover = false
      return
    }

    return dropdown.toggle()
  }

  closeDropdownIfHovered (dropdown: NgbDropdown) {
    if (this.openedOnHover === false) return

    dropdown.close()
    this.openedOnHover = false
  }

  toggleModal () {
    this.modalService.open(this.modal, { centered: true })
  }

  dismissOtherModals () {
    this.modalService.dismissAll()
  }

  getId (id: number | string = uniqueId()): string {
    return lowerFirst(this.constructor.name) + '_' + id
  }
}