/* eslint-disable @angular-eslint/prefer-on-push-component-change-detection */ import { AfterViewInit, Component, forwardRef, HostListener, Inject, Input, ViewChild } from '@angular/core'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { delay, tap } from 'rxjs/operators'; import { trackByFactory, ContextComponent } from '../../utils'; import { IListable } from '../models'; import { ListingComponent, ListingService } from '../index'; import { HasScrollbarDirective } from '../../scrollbar'; import { BehaviorSubject } from 'rxjs'; import { HelpModeService } from '../../help-mode'; interface TableContentTemplate { checkViewportSize: () => void, lastScrolledIndex: number, hasScrollbarDirective: () => void, noContent: boolean, sortedDisplayedEntities: any[], isHelpModeActive: boolean, } @Component({ selector: 'iqser-table-content', templateUrl: './table-content.component.html', styleUrls: ['./table-content.component.scss'], }) export class TableContentComponent extends ContextComponent implements AfterViewInit { @Input() itemSize!: number; @Input() itemMouseEnterFn?: (entity: T) => void; @Input() itemMouseLeaveFn?: (entity: T) => void; @Input() tableItemClasses?: Record boolean>; @Input() selectionEnabled!: boolean; readonly trackBy = trackByFactory(); @ViewChild(CdkVirtualScrollViewport, { static: true }) readonly scrollViewport!: CdkVirtualScrollViewport; @ViewChild(HasScrollbarDirective, { static: true }) readonly hasScrollbarDirective!: HasScrollbarDirective; private _lastScrolledIndex = 0; private _multiSelectActive$ = new BehaviorSubject(false); readonly #checkViewportSize$ = this.listingComponent.noContent$.pipe(tap(() => { setTimeout(() => { this.scrollViewport?.checkViewportSize(); }, 0); })); constructor( @Inject(forwardRef(() => ListingComponent)) readonly listingComponent: ListingComponent, readonly listingService: ListingService, readonly helpModeService: HelpModeService, ) { super(); } multiSelect(entity: T, $event: MouseEvent): void { if (this.selectionEnabled && this._multiSelectActive$.value) { $event.stopPropagation(); this.listingService.select(entity); } } ngAfterViewInit(): void { const lastScrolledIndex$ = this.scrollViewport.scrolledIndexChange.pipe(tap(index => (this._lastScrolledIndex = index))) const hasScrollbarDirective$ = this.listingService.displayedLength$ .pipe( delay(100), tap(() => this.hasScrollbarDirective.process()), ) super._initContext({ checkViewportSize: this.#checkViewportSize$, lastScrolledIndex: lastScrolledIndex$, hasScrollbarDirective: hasScrollbarDirective$, noContent: this.listingComponent.noContent$, sortedDisplayedEntities: this.listingComponent.sortedDisplayedEntities$, isHelpModeActive: this.helpModeService.isHelpModeActive$, }) } scrollToLastIndex(): void { this.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth'); } getTableItemClasses(entity: T): Record { const classes: Record = { 'table-item': true, pointer: !!entity.routerLink && entity.routerLink.length > 0, }; for (const key in this.tableItemClasses) { if (Object.prototype.hasOwnProperty.call(this.tableItemClasses, key)) { classes[key] = this.tableItemClasses[key](entity); } } return classes; } @HostListener('window:keydown.control') @HostListener('window:keydown.meta') private _enableMultiSelect() { this._multiSelectActive$.next(true); } @HostListener('window:keyup.control') @HostListener('window:keyup.meta') private _disableMultiSelect() { this._multiSelectActive$.next(false); } }