From 24e7916c6897bbb38e057cdf1a102286006be964 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Wed, 5 Feb 2020 20:54:37 +0100 Subject: Add ListOverflow component to prevent sub-menu overflow --- .../src/app/shared/misc/list-overflow.component.ts | 114 +++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 client/src/app/shared/misc/list-overflow.component.ts (limited to 'client/src/app/shared/misc/list-overflow.component.ts') diff --git a/client/src/app/shared/misc/list-overflow.component.ts b/client/src/app/shared/misc/list-overflow.component.ts new file mode 100644 index 000000000..4f92c0f7c --- /dev/null +++ b/client/src/app/shared/misc/list-overflow.component.ts @@ -0,0 +1,114 @@ +import { + Component, + Input, + TemplateRef, + ViewChildren, + ViewChild, + QueryList, + ChangeDetectionStrategy, + ElementRef, + ChangeDetectorRef, + HostListener +} from '@angular/core' +import { NgbModal, NgbDropdown } from '@ng-bootstrap/ng-bootstrap' +import { uniqueId, lowerFirst } from 'lodash-es' +import { ScreenService } from './screen.service' +import { take } from 'rxjs/operators' + +export interface ListOverflowItem { + label: string + routerLink: string | any[] +} + +@Component({ + selector: 'list-overflow', + templateUrl: './list-overflow.component.html', + styleUrls: [ './list-overflow.component.scss' ], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ListOverflowComponent { + @ViewChild('modal', { static: true }) modal: ElementRef + @ViewChild('itemsParent', { static: true }) parent: ElementRef + @ViewChildren('itemsRendered') itemsRendered: QueryList + @Input() items: T[] + @Input() itemTemplate: TemplateRef<{item: T}> + + showItemsUntilIndexExcluded: number + active = false + isInTouchScreen = false + isInMobileView = false + + private openedOnHover = false + + constructor ( + private cdr: ChangeDetectorRef, + private modalService: NgbModal, + private screenService: ScreenService + ) {} + + isMenuDisplayed () { + return !!this.showItemsUntilIndexExcluded + } + + @HostListener('window:resize', ['$event']) + onWindowResize () { + this.isInTouchScreen = !!this.screenService.isInTouchScreen() + this.isInMobileView = !!this.screenService.isInMobileView() + + const parentWidth = this.parent.nativeElement.getBoundingClientRect().width + let showItemsUntilIndexExcluded: number + let accWidth = 0 + + 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' + } + + 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 + } +} -- cgit v1.2.3