diff options
Diffstat (limited to 'client/src/app/shared')
3 files changed, 80 insertions, 0 deletions
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, |