-<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>
import { Notifier } from '@app/core'
import { RestService } from '@app/shared'
import { SortMeta } from 'primeng/api'
+import { Subject } from 'rxjs'
@Component({
selector: 'my-about-follows',
followersPagination: ComponentPagination = {
currentPage: 1,
- itemsPerPage: 40,
+ itemsPerPage: 20,
totalItems: null
}
followingsPagination: ComponentPagination = {
currentPage: 1,
- itemsPerPage: 40,
+ itemsPerPage: 20,
totalItems: null
}
order: -1
}
+ onDataSubject = new Subject<any[]>()
+
constructor (
private restService: RestService,
private notifier: Notifier,
this.followers = this.followers.concat(newFollowers)
this.followersPagination.totalItems = resultList.total
+
+ this.onDataSubject.next(newFollowers)
},
err => this.notifier.error(err.message)
this.followings = this.followings.concat(newFollowings)
this.followingsPagination.totalItems = resultList.total
+
+ this.onDataSubject.next(newFollowings)
},
err => this.notifier.error(err.message)
<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">
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'
}
videosSort: VideoSortField = '-publishedAt'
+ onChannelDataSubject = new Subject<any>()
+
private accountSub: Subscription
constructor (
this.videoChannels.push(videoChannel)
this.videos[videoChannel.id] = videos
+
+ this.onChannelDataSubject.next([ videoChannel ])
})
}
{{ 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">
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',
PluginType = PluginType
+ onDataSubject = new Subject<any[]>()
+
constructor (
private i18n: I18n,
private pluginService: PluginService,
res => {
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
+
+ this.onDataSubject.next(res.data)
},
err => this.notifier.error(err.message)
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">
installing: { [name: string]: boolean } = {}
pluginInstalled = false
+ onDataSubject = new Subject<any[]>()
+
private searchSubject = new Subject<string>()
constructor (
this.plugins = this.plugins.concat(res.data)
this.pagination.totalItems = res.total
+
+ this.onDataSubject.next(res.data)
},
err => {
<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"
<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" />
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',
totalItems: null
}
+ onDataSubject = new Subject<any[]>()
+
constructor (
private userSubscriptionService: UserSubscriptionService,
private notifier: Notifier
res => {
this.videoChannels = this.videoChannels.concat(res.data)
this.pagination.totalItems = res.total
+
+ this.onDataSubject.next(res.data)
},
error => this.notifier.error(error.message)
<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
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;
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'
pagination: ComponentPagination = {
currentPage: 1,
- itemsPerPage: 30,
+ itemsPerPage: 10,
totalItems: null
}
+ onDataSubject = new Subject<any[]>()
+
private videoPlaylistId: string | number
private paramsSub: Subscription
.subscribe(({ total, data }) => {
this.playlistElements = this.playlistElements.concat(data)
this.pagination.totalItems = total
+
+ this.onDataSubject.next(data)
})
}
</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"
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',
pagination: ComponentPagination = {
currentPage: 1,
- itemsPerPage: 10,
+ itemsPerPage: 5,
totalItems: null
}
+ onDataSubject = new Subject<any[]>()
+
private user: User
constructor (
}
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)
})
}
}
<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>
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'
totalItems: null
}
+ onDataSubject = new Subject<any[]>()
+
private videoChannelSub: Subscription
private videoChannel: VideoChannel
}
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)
})
}
}
<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">
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',
componentPagination: ComponentPagination
+ onDataSubject = new Subject<any[]>()
+
constructor (
private userNotificationService: UserNotificationService,
private notifier: Notifier
this.componentPagination.totalItems = result.total
this.notificationsLoaded.emit()
+
+ this.onDataSubject.next(result.data)
},
err => this.notifier.error(err.message)
load () {
forkJoin([
- this.videoPlaylistService.listAccountPlaylists(this.user.account, '-updatedAt'),
+ this.videoPlaylistService.listAccountPlaylists(this.user.account, undefined,'-updatedAt'),
this.videoPlaylistService.doesVideoExistInPlaylist(this.video.id)
])
.subscribe(
)
}
- 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(
<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;">
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'
blacklistInfo: false
}
+ onDataSubject = new Subject<any[]>()
+
protected abstract notifier: Notifier
protected abstract authService: AuthService
protected abstract route: ActivatedRoute
if (this.groupByDate) this.buildGroupedDateLabels()
this.onMoreVideos()
+
+ this.onDataSubject.next(data)
},
error => this.notifier.error(error.message)
-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>()
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()
}
}
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),
// 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() }
+ }
+
+ private getMaximumScroll () {
+ return this.container.scrollHeight - window.innerHeight
+ }
+
+ private hasScroll () {
+ return this.getMaximumScroll() > 0
+ }
+
+ private isScrollingDown (current: number) {
+ const result = this.lastCurrentBottom < current
- return { current: window.scrollY, maximumScroll: document.body.clientHeight - window.innerHeight }
+ this.lastCurrentBottom = current
+ return result
}
}
<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">
myInfiniteScroller
[autoInit]="true"
(nearOfBottom)="onNearOfBottom()"
+ [dataObservable]="onDataSubject.asObservable()"
>
<div #commentHighlightBlock id="highlighted-comment">
<my-video-comment
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'
syndicationItems: Syndication[] = []
+ onDataSubject = new Subject<any[]>()
+
private sub: Subscription
constructor (
res => {
this.comments = this.comments.concat(res.data)
this.componentPagination.totalItems = res.total
+
+ this.onDataSubject.next(res.data)
},
err => this.notifier.error(err.message)