70 lines
3.0 KiB
TypeScript
70 lines
3.0 KiB
TypeScript
import { ChangeDetectionStrategy, Component, HostListener, Input, OnInit } from '@angular/core';
|
|
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
import { delay, map, startWith } from 'rxjs/operators';
|
|
import { combineLatest, fromEvent, Observable } from 'rxjs';
|
|
import { Required, shareDistinctLast } from '../../utils';
|
|
|
|
const ButtonTypes = {
|
|
top: 'top',
|
|
bottom: 'bottom',
|
|
} as const;
|
|
|
|
type ButtonType = keyof typeof ButtonTypes;
|
|
|
|
@Component({
|
|
selector: 'iqser-scroll-button',
|
|
templateUrl: './scroll-button.component.html',
|
|
styleUrls: ['./scroll-button.component.scss'],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
})
|
|
export class ScrollButtonComponent implements OnInit {
|
|
readonly buttonType = ButtonTypes;
|
|
|
|
@Input() @Required() scrollViewport!: CdkVirtualScrollViewport;
|
|
@Input() @Required() itemSize!: number;
|
|
|
|
showScrollUp$?: Observable<boolean>;
|
|
showScrollDown$?: Observable<boolean>;
|
|
|
|
ngOnInit(): void {
|
|
const scrollSize = () => this.scrollViewport.getDataLength() * this.itemSize;
|
|
const scrollIsNeeded = () => this.scrollViewport.getViewportSize() < scrollSize();
|
|
const reachedEnd = (type: ButtonType) => this.scrollViewport.measureScrollOffset(type) < 0.5;
|
|
|
|
const showScrollUp = () => scrollIsNeeded() && !reachedEnd(ButtonTypes.top);
|
|
const showScrollDown = () => scrollIsNeeded() && !reachedEnd(ButtonTypes.bottom);
|
|
|
|
/** Force an initial emit, so combineLatest works */
|
|
const scrolled$ = this.scrollViewport.elementScrolled().pipe(startWith(null));
|
|
const resized$ = fromEvent(window, 'resize').pipe(startWith(null));
|
|
const rangeChange$ = this.scrollViewport.renderedRangeStream.pipe(startWith(null));
|
|
|
|
/** Delay so that we can wait for items to be rendered in viewport and get correct values */
|
|
const scroll$ = combineLatest([scrolled$, resized$, rangeChange$]).pipe(delay(0), shareDistinctLast());
|
|
|
|
this.showScrollUp$ = scroll$.pipe(map(showScrollUp));
|
|
this.showScrollDown$ = scroll$.pipe(map(showScrollDown));
|
|
}
|
|
|
|
scroll(type: ButtonType): void {
|
|
const viewportSize = (this.scrollViewport?.getViewportSize() - this.itemSize) * (type === ButtonTypes.top ? -1 : 1);
|
|
const scrollOffset = this.scrollViewport?.measureScrollOffset('top');
|
|
this.scrollViewport?.scrollToOffset(scrollOffset + viewportSize, 'smooth');
|
|
}
|
|
|
|
@HostListener('document:keyup', ['$event'])
|
|
spaceAndPageDownScroll(event: KeyboardEvent): void {
|
|
const target = event.target as EventTarget & { tagName: string };
|
|
if (['Space', 'PageDown'].includes(event.code) && target.tagName === 'BODY') {
|
|
this.scroll(ButtonTypes.bottom);
|
|
} else if (['PageUp'].includes(event.code) && target.tagName === 'BODY') {
|
|
this.scroll(ButtonTypes.top);
|
|
}
|
|
}
|
|
|
|
get helpModeKey (): string {
|
|
const screen = window.location.href.includes('/dossiers/') ? 'documents' : 'dossiers';
|
|
return `${screen}`;
|
|
}
|
|
}
|