Fix infinite scroll on big screens
This commit is contained in:
parent
dd570a34ff
commit
ad453580b2
|
@ -1,4 +1,4 @@
|
|||
<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
|
||||
<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div class="col-xl-6 col-md-12">
|
||||
<div i18n class="subtitle">Followers</div>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pa
|
|||
import { Notifier } from '@app/core'
|
||||
import { RestService } from '@app/shared'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'my-about-follows',
|
||||
|
@ -17,13 +18,13 @@ export class AboutFollowsComponent implements OnInit {
|
|||
|
||||
followersPagination: ComponentPagination = {
|
||||
currentPage: 1,
|
||||
itemsPerPage: 40,
|
||||
itemsPerPage: 20,
|
||||
totalItems: null
|
||||
}
|
||||
|
||||
followingsPagination: ComponentPagination = {
|
||||
currentPage: 1,
|
||||
itemsPerPage: 40,
|
||||
itemsPerPage: 20,
|
||||
totalItems: null
|
||||
}
|
||||
|
||||
|
@ -32,6 +33,8 @@ export class AboutFollowsComponent implements OnInit {
|
|||
order: -1
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
constructor (
|
||||
private restService: RestService,
|
||||
private notifier: Notifier,
|
||||
|
@ -78,6 +81,8 @@ export class AboutFollowsComponent implements OnInit {
|
|||
this.followers = this.followers.concat(newFollowers)
|
||||
|
||||
this.followersPagination.totalItems = resultList.total
|
||||
|
||||
this.onDataSubject.next(newFollowers)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
|
@ -94,6 +99,8 @@ export class AboutFollowsComponent implements OnInit {
|
|||
this.followings = this.followings.concat(newFollowings)
|
||||
|
||||
this.followingsPagination.totalItems = resultList.total
|
||||
|
||||
this.onDataSubject.next(newFollowings)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<div class="no-results" i18n *ngIf="channelPagination.totalItems === 0">This account does not have channels.</div>
|
||||
|
||||
<div class="channels" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true">
|
||||
<div class="channels" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onChannelDataSubject.asObservable()">
|
||||
<div class="section channel" *ngFor="let videoChannel of videoChannels">
|
||||
<div class="section-title">
|
||||
<a [routerLink]="getVideoChannelLink(videoChannel)" i18n-title title="See this video channel">
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Account } from '@app/shared/account/account.model'
|
|||
import { AccountService } from '@app/shared/account/account.service'
|
||||
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
|
||||
import { concatMap, map, switchMap, tap } from 'rxjs/operators'
|
||||
import { from, Subscription } from 'rxjs'
|
||||
import { from, Subject, Subscription } from 'rxjs'
|
||||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||
import { Video } from '@app/shared/video/video.model'
|
||||
import { AuthService } from '@app/core'
|
||||
|
@ -33,6 +33,8 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
videosSort: VideoSortField = '-publishedAt'
|
||||
|
||||
onChannelDataSubject = new Subject<any>()
|
||||
|
||||
private accountSub: Subscription
|
||||
|
||||
constructor (
|
||||
|
@ -75,6 +77,8 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
|
|||
this.videoChannels.push(videoChannel)
|
||||
|
||||
this.videos[videoChannel.id] = videos
|
||||
|
||||
this.onChannelDataSubject.next([ videoChannel ])
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{{ getNoResultMessage() }}
|
||||
</div>
|
||||
|
||||
<div class="plugins" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true">
|
||||
<div class="plugins" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div class="card plugin" *ngFor="let plugin of plugins">
|
||||
<div class="card-body">
|
||||
<div class="first-row">
|
||||
|
|
|
@ -8,6 +8,7 @@ import { PeerTubePlugin } from '@shared/models/plugins/peertube-plugin.model'
|
|||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { compareSemVer } from '@shared/core-utils/miscs/miscs'
|
||||
import { PluginService } from '@app/core/plugins/plugin.service'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'my-plugin-list-installed',
|
||||
|
@ -33,6 +34,8 @@ export class PluginListInstalledComponent implements OnInit {
|
|||
|
||||
PluginType = PluginType
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
constructor (
|
||||
private i18n: I18n,
|
||||
private pluginService: PluginService,
|
||||
|
@ -67,6 +70,8 @@ export class PluginListInstalledComponent implements OnInit {
|
|||
res => {
|
||||
this.plugins = this.plugins.concat(res.data)
|
||||
this.pagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
No results.
|
||||
</div>
|
||||
|
||||
<div class="plugins" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true">
|
||||
<div class="plugins" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div class="card plugin" *ngFor="let plugin of plugins">
|
||||
<div class="card-body">
|
||||
<div class="first-row">
|
||||
|
|
|
@ -36,6 +36,8 @@ export class PluginSearchComponent implements OnInit {
|
|||
installing: { [name: string]: boolean } = {}
|
||||
pluginInstalled = false
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
private searchSubject = new Subject<string>()
|
||||
|
||||
constructor (
|
||||
|
@ -90,6 +92,8 @@ export class PluginSearchComponent implements OnInit {
|
|||
|
||||
this.plugins = this.plugins.concat(res.data)
|
||||
this.pagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
},
|
||||
|
||||
err => {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<div class="no-history" i18n *ngIf="pagination.totalItems === 0">You don't have videos history yet.</div>
|
||||
|
||||
<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" class="videos">
|
||||
<div myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()" class="videos">
|
||||
<div class="video" *ngFor="let video of videos">
|
||||
<my-video-miniature
|
||||
[video]="video" [displayAsRow]="true"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="no-results" i18n *ngIf="pagination.totalItems === 0">You don't have any subscriptions yet.</div>
|
||||
|
||||
<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
|
||||
<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div *ngFor="let videoChannel of videoChannels" class="video-channel">
|
||||
<a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]">
|
||||
<img [src]="videoChannel.avatarUrl" alt="Avatar" />
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Notifier } from '@app/core'
|
|||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||
import { UserSubscriptionService } from '@app/shared/user-subscription'
|
||||
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-subscriptions',
|
||||
|
@ -18,6 +19,8 @@ export class MyAccountSubscriptionsComponent implements OnInit {
|
|||
totalItems: null
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
constructor (
|
||||
private userSubscriptionService: UserSubscriptionService,
|
||||
private notifier: Notifier
|
||||
|
@ -33,6 +36,8 @@ export class MyAccountSubscriptionsComponent implements OnInit {
|
|||
res => {
|
||||
this.videoChannels = this.videoChannels.concat(res.data)
|
||||
this.pagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
},
|
||||
|
||||
error => this.notifier.error(error.message)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<div
|
||||
class="videos" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()"
|
||||
cdkDropList (cdkDropListDropped)="drop($event)"
|
||||
cdkDropList (cdkDropListDropped)="drop($event)" [dataObservable]="onDataSubject.asObservable()"
|
||||
>
|
||||
<div class="video" *ngFor="let playlistElement of playlistElements; trackBy: trackByFn" cdkDrag>
|
||||
<my-video-playlist-element-miniature
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
margin-left: -15px;
|
||||
margin-top: -$sub-menu-margin-bottom;
|
||||
|
||||
padding: $sub-menu-margin-bottom 0;
|
||||
padding: $sub-menu-margin-bottom 0 -15px 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Notifier, ServerService } from '@app/core'
|
|||
import { AuthService } from '../../core/auth'
|
||||
import { ConfirmService } from '../../core/confirm'
|
||||
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Subject, Subscription } from 'rxjs'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
|
||||
import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
|
||||
|
@ -22,10 +22,12 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
|
|||
|
||||
pagination: ComponentPagination = {
|
||||
currentPage: 1,
|
||||
itemsPerPage: 30,
|
||||
itemsPerPage: 10,
|
||||
totalItems: null
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
private videoPlaylistId: string | number
|
||||
private paramsSub: Subscription
|
||||
|
||||
|
@ -102,6 +104,8 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
|
|||
.subscribe(({ total, data }) => {
|
||||
this.playlistElements = this.playlistElements.concat(data)
|
||||
this.pagination.totalItems = total
|
||||
|
||||
this.onDataSubject.next(data)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<div class="video-playlists" myInfiniteScroller (nearOfBottom)="onNearOfBottom()">
|
||||
<div class="video-playlists" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div *ngFor="let playlist of videoPlaylists" class="video-playlist">
|
||||
<div class="miniature-wrapper">
|
||||
<my-video-playlist-miniature [playlist]="playlist" [toManage]="true" [displayChannel]="true" [displayDescription]="true" [displayPrivacy]="true"
|
||||
|
|
|
@ -9,6 +9,7 @@ import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
|
|||
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
|
||||
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
|
||||
import { VideoPlaylistType } from '@shared/models'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-video-playlists',
|
||||
|
@ -20,10 +21,12 @@ export class MyAccountVideoPlaylistsComponent implements OnInit {
|
|||
|
||||
pagination: ComponentPagination = {
|
||||
currentPage: 1,
|
||||
itemsPerPage: 10,
|
||||
itemsPerPage: 5,
|
||||
totalItems: null
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
private user: User
|
||||
|
||||
constructor (
|
||||
|
@ -78,11 +81,15 @@ export class MyAccountVideoPlaylistsComponent implements OnInit {
|
|||
}
|
||||
|
||||
private loadVideoPlaylists () {
|
||||
const playlistsObservable = this.videoPlaylistService.listAccountPlaylists(this.user.account, this.pagination, '-updatedAt')
|
||||
|
||||
this.authService.userInformationLoaded
|
||||
.pipe(flatMap(() => this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt')))
|
||||
.pipe(flatMap(() => playlistsObservable))
|
||||
.subscribe(res => {
|
||||
this.videoPlaylists = this.videoPlaylists.concat(res.data)
|
||||
this.pagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<div i18n class="no-results" *ngIf="pagination.totalItems === 0">This channel does not have playlists.</div>
|
||||
|
||||
<div class="video-playlist" myInfiniteScroller (nearOfBottom)="onNearOfBottom()">
|
||||
<div class="video-playlist" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div *ngFor="let playlist of videoPlaylists">
|
||||
<my-video-playlist-miniature [playlist]="playlist" [toManage]="false"></my-video-playlist-miniature>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'
|
|||
import { ConfirmService } from '../../core/confirm'
|
||||
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
|
||||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Subject, Subscription } from 'rxjs'
|
||||
import { Notifier } from '@app/core'
|
||||
import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
|
||||
import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
|
||||
|
@ -22,6 +22,8 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy {
|
|||
totalItems: null
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
private videoChannelSub: Subscription
|
||||
private videoChannel: VideoChannel
|
||||
|
||||
|
@ -53,10 +55,12 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
private loadVideoPlaylists () {
|
||||
this.videoPlaylistService.listChannelPlaylists(this.videoChannel)
|
||||
this.videoPlaylistService.listChannelPlaylists(this.videoChannel, this.pagination)
|
||||
.subscribe(res => {
|
||||
this.videoPlaylists = this.videoPlaylists.concat(res.data)
|
||||
this.pagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div *ngIf="componentPagination.totalItems === 0" class="no-notification" i18n>You don't have notifications.</div>
|
||||
|
||||
<div class="notifications" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
|
||||
<div class="notifications" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
|
||||
<div *ngFor="let notification of notifications" class="notification" [ngClass]="{ unread: !notification.read }" (click)="markAsRead(notification)">
|
||||
|
||||
<ng-container [ngSwitch]="notification.type">
|
||||
|
|
|
@ -4,6 +4,7 @@ import { UserNotificationType } from '../../../../../shared'
|
|||
import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
|
||||
import { Notifier } from '@app/core'
|
||||
import { UserNotification } from '@app/shared/users/user-notification.model'
|
||||
import { Subject } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'my-user-notifications',
|
||||
|
@ -24,6 +25,8 @@ export class UserNotificationsComponent implements OnInit {
|
|||
|
||||
componentPagination: ComponentPagination
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
constructor (
|
||||
private userNotificationService: UserNotificationService,
|
||||
private notifier: Notifier
|
||||
|
@ -47,6 +50,8 @@ export class UserNotificationsComponent implements OnInit {
|
|||
this.componentPagination.totalItems = result.total
|
||||
|
||||
this.notificationsLoaded.emit()
|
||||
|
||||
this.onDataSubject.next(result.data)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
|
|
|
@ -83,7 +83,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
|
||||
load () {
|
||||
forkJoin([
|
||||
this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'),
|
||||
this.videoPlaylistService.listAccountPlaylists(this.user.account, undefined,'-updatedAt'),
|
||||
this.videoPlaylistService.doesVideoExistInPlaylist(this.video.id)
|
||||
])
|
||||
.subscribe(
|
||||
|
|
|
@ -45,21 +45,28 @@ export class VideoPlaylistService {
|
|||
)
|
||||
}
|
||||
|
||||
listChannelPlaylists (videoChannel: VideoChannel): Observable<ResultList<VideoPlaylist>> {
|
||||
listChannelPlaylists (videoChannel: VideoChannel, componentPagination: ComponentPagination): Observable<ResultList<VideoPlaylist>> {
|
||||
const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/video-playlists'
|
||||
const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
|
||||
|
||||
return this.authHttp.get<ResultList<VideoPlaylist>>(url)
|
||||
let params = new HttpParams()
|
||||
params = this.restService.addRestGetParams(params, pagination)
|
||||
|
||||
return this.authHttp.get<ResultList<VideoPlaylist>>(url, { params })
|
||||
.pipe(
|
||||
switchMap(res => this.extractPlaylists(res)),
|
||||
catchError(err => this.restExtractor.handleError(err))
|
||||
)
|
||||
}
|
||||
|
||||
listAccountPlaylists (account: Account, sort: string): Observable<ResultList<VideoPlaylist>> {
|
||||
listAccountPlaylists (account: Account, componentPagination: ComponentPagination, sort: string): Observable<ResultList<VideoPlaylist>> {
|
||||
const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-playlists'
|
||||
const pagination = componentPagination
|
||||
? this.restService.componentPaginationToRestPagination(componentPagination)
|
||||
: undefined
|
||||
|
||||
let params = new HttpParams()
|
||||
params = this.restService.addRestGetParams(params, undefined, sort)
|
||||
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||
|
||||
return this.authHttp.get<ResultList<VideoPlaylist>>(url, { params })
|
||||
.pipe(
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<div class="no-results" i18n *ngIf="pagination.totalItems === 0">No results.</div>
|
||||
<div
|
||||
myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true"
|
||||
myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" [dataObservable]="onDataSubject.asObservable()"
|
||||
class="videos"
|
||||
>
|
||||
<ng-container *ngFor="let video of videos; trackBy: videoById;">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { debounceTime, first, tap } from 'rxjs/operators'
|
||||
import { OnDestroy, OnInit } from '@angular/core'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { fromEvent, Observable, of, Subscription } from 'rxjs'
|
||||
import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs'
|
||||
import { AuthService } from '../../core/auth'
|
||||
import { ComponentPagination } from '../rest/component-pagination.model'
|
||||
import { VideoSortField } from './sort-field.type'
|
||||
|
@ -59,6 +59,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
|
|||
blacklistInfo: false
|
||||
}
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
protected abstract notifier: Notifier
|
||||
protected abstract authService: AuthService
|
||||
protected abstract route: ActivatedRoute
|
||||
|
@ -147,6 +149,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
|
|||
if (this.groupByDate) this.buildGroupedDateLabels()
|
||||
|
||||
this.onMoreVideos()
|
||||
|
||||
this.onDataSubject.next(data)
|
||||
},
|
||||
|
||||
error => this.notifier.error(error.message)
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { distinct, distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators'
|
||||
import { Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
|
||||
import { fromEvent, Subscription } from 'rxjs'
|
||||
import { distinctUntilChanged, filter, map, share, startWith, tap, throttleTime } from 'rxjs/operators'
|
||||
import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
|
||||
import { fromEvent, Observable, Subscription } from 'rxjs'
|
||||
|
||||
@Directive({
|
||||
selector: '[myInfiniteScroller]'
|
||||
})
|
||||
export class InfiniteScrollerDirective implements OnInit, OnDestroy {
|
||||
export class InfiniteScrollerDirective implements OnInit, OnDestroy, AfterContentChecked {
|
||||
@Input() percentLimit = 70
|
||||
@Input() autoInit = false
|
||||
@Input() onItself = false
|
||||
@Input() dataObservable: Observable<any[]>
|
||||
|
||||
@Output() nearOfBottom = new EventEmitter<void>()
|
||||
|
||||
|
@ -17,10 +18,22 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
|
|||
private scrollDownSub: Subscription
|
||||
private container: HTMLElement
|
||||
|
||||
private checkScroll = false
|
||||
|
||||
constructor (private el: ElementRef) {
|
||||
this.decimalLimit = this.percentLimit / 100
|
||||
}
|
||||
|
||||
ngAfterContentChecked () {
|
||||
if (this.checkScroll) {
|
||||
this.checkScroll = false
|
||||
|
||||
console.log('Checking if the initial state has a scroll.')
|
||||
|
||||
if (this.hasScroll() === false) this.nearOfBottom.emit()
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
if (this.autoInit === true) return this.initialize()
|
||||
}
|
||||
|
@ -30,14 +43,15 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
initialize () {
|
||||
if (this.onItself) {
|
||||
this.container = this.el.nativeElement
|
||||
}
|
||||
this.container = this.onItself
|
||||
? this.el.nativeElement
|
||||
: document.documentElement
|
||||
|
||||
// Emit the last value
|
||||
const throttleOptions = { leading: true, trailing: true }
|
||||
|
||||
const scrollObservable = fromEvent(this.container || window, 'scroll')
|
||||
const scrollableElement = this.onItself ? this.container : window
|
||||
const scrollObservable = fromEvent(scrollableElement, 'scroll')
|
||||
.pipe(
|
||||
startWith(null as string), // FIXME: typings
|
||||
throttleTime(200, undefined, throttleOptions),
|
||||
|
@ -49,23 +63,34 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
|
|||
// Scroll Down
|
||||
this.scrollDownSub = scrollObservable
|
||||
.pipe(
|
||||
// Check we scroll down
|
||||
filter(({ current }) => {
|
||||
const res = this.lastCurrentBottom < current
|
||||
|
||||
this.lastCurrentBottom = current
|
||||
return res
|
||||
}),
|
||||
filter(({ current, maximumScroll }) => maximumScroll <= 0 || (current / maximumScroll) > this.decimalLimit)
|
||||
filter(({ current }) => this.isScrollingDown(current)),
|
||||
filter(({ current, maximumScroll }) => (current / maximumScroll) > this.decimalLimit)
|
||||
)
|
||||
.subscribe(() => this.nearOfBottom.emit())
|
||||
|
||||
if (this.dataObservable) {
|
||||
this.dataObservable
|
||||
.pipe(filter(d => d.length !== 0))
|
||||
.subscribe(() => this.checkScroll = true)
|
||||
}
|
||||
}
|
||||
|
||||
private getScrollInfo () {
|
||||
if (this.container) {
|
||||
return { current: this.container.scrollTop, maximumScroll: this.container.scrollHeight }
|
||||
}
|
||||
return { current: this.container.scrollTop, maximumScroll: this.getMaximumScroll() }
|
||||
}
|
||||
|
||||
return { current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight }
|
||||
private getMaximumScroll () {
|
||||
return this.container.scrollHeight - window.innerHeight
|
||||
}
|
||||
|
||||
private hasScroll () {
|
||||
return this.getMaximumScroll() > 0
|
||||
}
|
||||
|
||||
private isScrollingDown (current: number) {
|
||||
const result = this.lastCurrentBottom < current
|
||||
|
||||
this.lastCurrentBottom = current
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="no-results" i18n *ngIf="pagination.totalItems === 0">No results.</div>
|
||||
|
||||
<div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" class="videos">
|
||||
<div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()" class="videos">
|
||||
<div class="video" *ngFor="let video of videos; let i = index; trackBy: videoById">
|
||||
|
||||
<div class="checkbox-container">
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
myInfiniteScroller
|
||||
[autoInit]="true"
|
||||
(nearOfBottom)="onNearOfBottom()"
|
||||
[dataObservable]="onDataSubject.asObservable()"
|
||||
>
|
||||
<div #commentHighlightBlock id="highlighted-comment">
|
||||
<my-video-comment
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ConfirmService, Notifier } from '@app/core'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Subject, Subscription } from 'rxjs'
|
||||
import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model'
|
||||
import { AuthService } from '../../../core/auth'
|
||||
import { ComponentPagination, hasMoreItems } from '../../../shared/rest/component-pagination.model'
|
||||
|
@ -38,6 +38,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
syndicationItems: Syndication[] = []
|
||||
|
||||
onDataSubject = new Subject<any[]>()
|
||||
|
||||
private sub: Subscription
|
||||
|
||||
constructor (
|
||||
|
@ -124,6 +126,8 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
|
|||
res => {
|
||||
this.comments = this.comments.concat(res.data)
|
||||
this.componentPagination.totalItems = res.total
|
||||
|
||||
this.onDataSubject.next(res.data)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
|
|
Loading…
Reference in New Issue