common-ui/src/lib/listing/table-content/table-content.component.ts
2022-07-21 13:48:51 +03:00

108 lines
4.1 KiB
TypeScript

/* 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<T extends IListable> extends ContextComponent<TableContentTemplate> implements AfterViewInit {
@Input() itemSize!: number;
@Input() itemMouseEnterFn?: (entity: T) => void;
@Input() itemMouseLeaveFn?: (entity: T) => void;
@Input() tableItemClasses?: Record<string, (e: T) => boolean>;
@Input() selectionEnabled!: boolean;
readonly trackBy = trackByFactory<T>();
@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<T>,
readonly listingService: ListingService<T>,
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<string, boolean> {
const classes: Record<string, boolean> = {
'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);
}
}