From 439b6b7bfb5243f016135ccbd13a3491741cf809 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 21 Mar 2022 11:40:25 +0100 Subject: Lazy load charts when listing my channels --- .../shared-main/angular/defer-loading.directive.ts | 76 ++++++++++++++++++++++ client/src/app/shared/shared-main/angular/index.ts | 1 + .../app/shared/shared-main/shared-main.module.ts | 3 + 3 files changed, 80 insertions(+) create mode 100644 client/src/app/shared/shared-main/angular/defer-loading.directive.ts (limited to 'client/src/app/shared') diff --git a/client/src/app/shared/shared-main/angular/defer-loading.directive.ts b/client/src/app/shared/shared-main/angular/defer-loading.directive.ts new file mode 100644 index 000000000..9a10e90e3 --- /dev/null +++ b/client/src/app/shared/shared-main/angular/defer-loading.directive.ts @@ -0,0 +1,76 @@ +import * as debug from 'debug' +import { + AfterViewInit, + ChangeDetectorRef, + ContentChild, + Directive, + ElementRef, + EmbeddedViewRef, + EventEmitter, + OnDestroy, + Output, + TemplateRef, + ViewContainerRef +} from '@angular/core' + +const logger = debug('peertube:main:DeferLoadingDirective') + +@Directive({ + selector: '[myDeferLoading]' +}) +export class DeferLoadingDirective implements AfterViewInit, OnDestroy { + @ContentChild(TemplateRef) template: TemplateRef + + @Output() loaded: EventEmitter = new EventEmitter() + + view: EmbeddedViewRef + + private observer: IntersectionObserver + + constructor ( + private el: ElementRef, + private viewContainer: ViewContainerRef, + private cd: ChangeDetectorRef + ) { } + + ngAfterViewInit () { + if (this.hasIncompatibleBrowser()) { + return this.load() + } + + this.observer = new IntersectionObserver(entries => { + const entry = entries[0] + if (!entry.isIntersecting || entry.target !== this.el.nativeElement) return + + this.observer.unobserve(this.el.nativeElement) + this.load() + }, { threshold: 0.1 }) + + this.observer.observe(this.el.nativeElement) + } + + load () { + if (this.isLoaded()) return + + logger('Loading component') + + this.viewContainer.clear() + this.view = this.viewContainer.createEmbeddedView(this.template, {}, 0) + this.loaded.emit() + this.cd.detectChanges() + } + + isLoaded () { + return this.view != null + } + + ngOnDestroy () { + this.view = null + + if (this.observer) this.observer.disconnect() + } + + private hasIncompatibleBrowser () { + return !('IntersectionObserver' in window) + } +} diff --git a/client/src/app/shared/shared-main/angular/index.ts b/client/src/app/shared/shared-main/angular/index.ts index 069b7f654..4b87c2952 100644 --- a/client/src/app/shared/shared-main/angular/index.ts +++ b/client/src/app/shared/shared-main/angular/index.ts @@ -1,5 +1,6 @@ export * from './autofocus.directive' export * from './bytes.pipe' +export * from './defer-loading.directive' export * from './duration-formatter.pipe' export * from './from-now.pipe' export * from './infinite-scroller.directive' diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts index 10fc364b3..d83af9a66 100644 --- a/client/src/app/shared/shared-main/shared-main.module.ts +++ b/client/src/app/shared/shared-main/shared-main.module.ts @@ -21,6 +21,7 @@ import { AccountService } from './account' import { AutofocusDirective, BytesPipe, + DeferLoadingDirective, DurationFormatterPipe, FromNowPipe, InfiniteScrollerDirective, @@ -80,6 +81,7 @@ import { VideoChannelService } from './video-channel' BytesPipe, DurationFormatterPipe, AutofocusDirective, + DeferLoadingDirective, InfiniteScrollerDirective, PeerTubeTemplateDirective, @@ -139,6 +141,7 @@ import { VideoChannelService } from './video-channel' NumberFormatterPipe, DurationFormatterPipe, AutofocusDirective, + DeferLoadingDirective, InfiniteScrollerDirective, PeerTubeTemplateDirective, -- cgit v1.2.3