diff options
5 files changed, 94 insertions, 5 deletions
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html index c1ded0f6d..89327b065 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.html | |||
@@ -41,8 +41,16 @@ | |||
41 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> | 41 | <my-delete-button label (click)="deleteVideoChannel(videoChannel)"></my-delete-button> |
42 | </div> | 42 | </div> |
43 | 43 | ||
44 | <div *ngIf="!isInSmallView" class="w-100 d-flex justify-content-end"> | 44 | <div *ngIf="!isInSmallView" class="w-100 d-flex justify-content-end chart-container"> |
45 | <p-chart *ngIf="chartOptions && videoChannelsChartData && videoChannelsChartData[i]" type="line" [data]="videoChannelsChartData[i]" [options]="chartOptions" width="40vw" height="100px"></p-chart> | 45 | <div myDeferLoading> |
46 | <ng-template> | ||
47 | <p-chart | ||
48 | *ngIf="chartOptions && videoChannelsChartData && videoChannelsChartData[i]" | ||
49 | width="40vw" height="100px" | ||
50 | type="line" [data]="videoChannelsChartData[i]" [options]="chartOptions" | ||
51 | ></p-chart> | ||
52 | </ng-template> | ||
53 | </div> | ||
46 | </div> | 54 | </div> |
47 | </div> | 55 | </div> |
48 | </div> | 56 | </div> |
diff --git a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss index 484355967..ab80f3d01 100644 --- a/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss +++ b/client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss | |||
@@ -62,9 +62,10 @@ my-edit-button { | |||
62 | min-width: 190px; | 62 | min-width: 190px; |
63 | } | 63 | } |
64 | 64 | ||
65 | ::ng-deep .chartjs-render-monitor { | 65 | .chart-container { |
66 | position: relative; | 66 | // Sync these values with the template |
67 | top: 1px; | 67 | width: 40vw; |
68 | height: 100px; | ||
68 | } | 69 | } |
69 | 70 | ||
70 | .video-channels-header { | 71 | .video-channels-header { |
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 @@ | |||
1 | import * as debug from 'debug' | ||
2 | import { | ||
3 | AfterViewInit, | ||
4 | ChangeDetectorRef, | ||
5 | ContentChild, | ||
6 | Directive, | ||
7 | ElementRef, | ||
8 | EmbeddedViewRef, | ||
9 | EventEmitter, | ||
10 | OnDestroy, | ||
11 | Output, | ||
12 | TemplateRef, | ||
13 | ViewContainerRef | ||
14 | } from '@angular/core' | ||
15 | |||
16 | const logger = debug('peertube:main:DeferLoadingDirective') | ||
17 | |||
18 | @Directive({ | ||
19 | selector: '[myDeferLoading]' | ||
20 | }) | ||
21 | export class DeferLoadingDirective implements AfterViewInit, OnDestroy { | ||
22 | @ContentChild(TemplateRef) template: TemplateRef<any> | ||
23 | |||
24 | @Output() loaded: EventEmitter<any> = new EventEmitter() | ||
25 | |||
26 | view: EmbeddedViewRef<any> | ||
27 | |||
28 | private observer: IntersectionObserver | ||
29 | |||
30 | constructor ( | ||
31 | private el: ElementRef, | ||
32 | private viewContainer: ViewContainerRef, | ||
33 | private cd: ChangeDetectorRef | ||
34 | ) { } | ||
35 | |||
36 | ngAfterViewInit () { | ||
37 | if (this.hasIncompatibleBrowser()) { | ||
38 | return this.load() | ||
39 | } | ||
40 | |||
41 | this.observer = new IntersectionObserver(entries => { | ||
42 | const entry = entries[0] | ||
43 | if (!entry.isIntersecting || entry.target !== this.el.nativeElement) return | ||
44 | |||
45 | this.observer.unobserve(this.el.nativeElement) | ||
46 | this.load() | ||
47 | }, { threshold: 0.1 }) | ||
48 | |||
49 | this.observer.observe(this.el.nativeElement) | ||
50 | } | ||
51 | |||
52 | load () { | ||
53 | if (this.isLoaded()) return | ||
54 | |||
55 | logger('Loading component') | ||
56 | |||
57 | this.viewContainer.clear() | ||
58 | this.view = this.viewContainer.createEmbeddedView(this.template, {}, 0) | ||
59 | this.loaded.emit() | ||
60 | this.cd.detectChanges() | ||
61 | } | ||
62 | |||
63 | isLoaded () { | ||
64 | return this.view != null | ||
65 | } | ||
66 | |||
67 | ngOnDestroy () { | ||
68 | this.view = null | ||
69 | |||
70 | if (this.observer) this.observer.disconnect() | ||
71 | } | ||
72 | |||
73 | private hasIncompatibleBrowser () { | ||
74 | return !('IntersectionObserver' in window) | ||
75 | } | ||
76 | } | ||
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 @@ | |||
1 | export * from './autofocus.directive' | 1 | export * from './autofocus.directive' |
2 | export * from './bytes.pipe' | 2 | export * from './bytes.pipe' |
3 | export * from './defer-loading.directive' | ||
3 | export * from './duration-formatter.pipe' | 4 | export * from './duration-formatter.pipe' |
4 | export * from './from-now.pipe' | 5 | export * from './from-now.pipe' |
5 | export * from './infinite-scroller.directive' | 6 | 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' | |||
21 | import { | 21 | import { |
22 | AutofocusDirective, | 22 | AutofocusDirective, |
23 | BytesPipe, | 23 | BytesPipe, |
24 | DeferLoadingDirective, | ||
24 | DurationFormatterPipe, | 25 | DurationFormatterPipe, |
25 | FromNowPipe, | 26 | FromNowPipe, |
26 | InfiniteScrollerDirective, | 27 | InfiniteScrollerDirective, |
@@ -80,6 +81,7 @@ import { VideoChannelService } from './video-channel' | |||
80 | BytesPipe, | 81 | BytesPipe, |
81 | DurationFormatterPipe, | 82 | DurationFormatterPipe, |
82 | AutofocusDirective, | 83 | AutofocusDirective, |
84 | DeferLoadingDirective, | ||
83 | 85 | ||
84 | InfiniteScrollerDirective, | 86 | InfiniteScrollerDirective, |
85 | PeerTubeTemplateDirective, | 87 | PeerTubeTemplateDirective, |
@@ -139,6 +141,7 @@ import { VideoChannelService } from './video-channel' | |||
139 | NumberFormatterPipe, | 141 | NumberFormatterPipe, |
140 | DurationFormatterPipe, | 142 | DurationFormatterPipe, |
141 | AutofocusDirective, | 143 | AutofocusDirective, |
144 | DeferLoadingDirective, | ||
142 | 145 | ||
143 | InfiniteScrollerDirective, | 146 | InfiniteScrollerDirective, |
144 | PeerTubeTemplateDirective, | 147 | PeerTubeTemplateDirective, |