mirror of https://github.com/Chocobozzz/PeerTube
Add auto scroll to videos list
parent
9bf9d2a5c2
commit
2bbb34127f
|
@ -71,6 +71,7 @@
|
||||||
"ngc-webpack": "3.2.2",
|
"ngc-webpack": "3.2.2",
|
||||||
"ngx-bootstrap": "2.0.0-beta.9",
|
"ngx-bootstrap": "2.0.0-beta.9",
|
||||||
"ngx-chips": "1.5.3",
|
"ngx-chips": "1.5.3",
|
||||||
|
"ngx-infinite-scroll": "^0.7.0",
|
||||||
"ngx-pipes": "^2.0.5",
|
"ngx-pipes": "^2.0.5",
|
||||||
"node-sass": "^4.1.1",
|
"node-sass": "^4.1.1",
|
||||||
"normalize.css": "^7.0.0",
|
"normalize.css": "^7.0.0",
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { PreloadSelectedModulesList } from './core'
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirectTo: '/videos/list',
|
redirectTo: '/videos/trending',
|
||||||
pathMatch: 'full'
|
pathMatch: 'full'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Pipe, PipeTransform } from '@angular/core'
|
import { Pipe, PipeTransform } from '@angular/core'
|
||||||
|
|
||||||
// Thanks: https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
|
// Thanks: https://stackoverflow.com/questions/3177836/how-to-format-time-since-xxx-e-g-4-minutes-ago-similar-to-stack-exchange-site
|
||||||
|
|
||||||
@Pipe({name: 'fromNow'})
|
@Pipe({name: 'fromNow'})
|
||||||
export class FromNowPipe implements PipeTransform {
|
export class FromNowPipe implements PipeTransform {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
|
|
||||||
import { Search } from './search.model'
|
import { Search } from './search.model'
|
||||||
import { SearchField } from './search-field.type'
|
|
||||||
import { SearchService } from './search.service'
|
import { SearchService } from './search.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -12,12 +10,6 @@ import { SearchService } from './search.service'
|
||||||
})
|
})
|
||||||
|
|
||||||
export class SearchComponent implements OnInit {
|
export class SearchComponent implements OnInit {
|
||||||
fieldChoices = {
|
|
||||||
name: 'Name',
|
|
||||||
account: 'Account',
|
|
||||||
host: 'Host',
|
|
||||||
tags: 'Tags'
|
|
||||||
}
|
|
||||||
searchCriteria: Search = {
|
searchCriteria: Search = {
|
||||||
field: 'name',
|
field: 'name',
|
||||||
value: ''
|
value: ''
|
||||||
|
@ -40,30 +32,11 @@ export class SearchComponent implements OnInit {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get choiceKeys () {
|
|
||||||
return Object.keys(this.fieldChoices)
|
|
||||||
}
|
|
||||||
|
|
||||||
choose ($event: MouseEvent, choice: SearchField) {
|
|
||||||
$event.preventDefault()
|
|
||||||
$event.stopPropagation()
|
|
||||||
|
|
||||||
this.searchCriteria.field = choice
|
|
||||||
|
|
||||||
if (this.searchCriteria.value) {
|
|
||||||
this.doSearch()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doSearch () {
|
doSearch () {
|
||||||
if (this.router.url.indexOf('/videos/list') === -1) {
|
// if (this.router.url.indexOf('/videos/list') === -1) {
|
||||||
this.router.navigate([ '/videos/list' ])
|
// this.router.navigate([ '/videos/list' ])
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.searchService.searchUpdated.next(this.searchCriteria)
|
this.searchService.searchUpdated.next(this.searchCriteria)
|
||||||
}
|
}
|
||||||
|
|
||||||
getStringChoice (choiceKey: SearchField) {
|
|
||||||
return this.fieldChoices[choiceKey]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,20 @@ import { RouterModule } from '@angular/router'
|
||||||
|
|
||||||
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
|
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'
|
||||||
import { ModalModule } from 'ngx-bootstrap/modal'
|
import { ModalModule } from 'ngx-bootstrap/modal'
|
||||||
import { PaginationModule } from 'ngx-bootstrap/pagination'
|
|
||||||
import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
|
import { ProgressbarModule } from 'ngx-bootstrap/progressbar'
|
||||||
import { BytesPipe, KeysPipe } from 'ngx-pipes'
|
import { BytesPipe, KeysPipe } from 'ngx-pipes'
|
||||||
import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
|
import { SharedModule as PrimeSharedModule } from 'primeng/components/common/shared'
|
||||||
import { DataTableModule } from 'primeng/components/datatable/datatable'
|
import { DataTableModule } from 'primeng/components/datatable/datatable'
|
||||||
|
|
||||||
import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
import { AUTH_INTERCEPTOR_PROVIDER } from './auth'
|
||||||
|
import { FromNowPipe } from './misc/from-now.pipe'
|
||||||
import { LoaderComponent } from './misc/loader.component'
|
import { LoaderComponent } from './misc/loader.component'
|
||||||
|
import { NumberFormatterPipe } from './misc/number-formatter.pipe'
|
||||||
import { RestExtractor, RestService } from './rest'
|
import { RestExtractor, RestService } from './rest'
|
||||||
import { SearchComponent, SearchService } from './search'
|
import { SearchComponent, SearchService } from './search'
|
||||||
import { UserService } from './users'
|
import { UserService } from './users'
|
||||||
import { VideoAbuseService } from './video-abuse'
|
import { VideoAbuseService } from './video-abuse'
|
||||||
import { VideoBlacklistService } from './video-blacklist'
|
import { VideoBlacklistService } from './video-blacklist'
|
||||||
import { NumberFormatterPipe } from './misc/number-formatter.pipe'
|
|
||||||
import { FromNowPipe } from './misc/from-now.pipe'
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -32,7 +31,6 @@ import { FromNowPipe } from './misc/from-now.pipe'
|
||||||
|
|
||||||
BsDropdownModule.forRoot(),
|
BsDropdownModule.forRoot(),
|
||||||
ModalModule.forRoot(),
|
ModalModule.forRoot(),
|
||||||
PaginationModule.forRoot(),
|
|
||||||
ProgressbarModule.forRoot(),
|
ProgressbarModule.forRoot(),
|
||||||
|
|
||||||
DataTableModule,
|
DataTableModule,
|
||||||
|
@ -57,7 +55,6 @@ import { FromNowPipe } from './misc/from-now.pipe'
|
||||||
|
|
||||||
BsDropdownModule,
|
BsDropdownModule,
|
||||||
ModalModule,
|
ModalModule,
|
||||||
PaginationModule,
|
|
||||||
ProgressbarModule,
|
ProgressbarModule,
|
||||||
DataTableModule,
|
DataTableModule,
|
||||||
PrimeSharedModule,
|
PrimeSharedModule,
|
||||||
|
|
|
@ -2,15 +2,17 @@
|
||||||
{{ titlePage }}
|
{{ titlePage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="videos-miniatures">
|
<div
|
||||||
|
class="videos-miniatures"
|
||||||
|
infiniteScroll
|
||||||
|
[infiniteScrollUpDistance]="1.5"
|
||||||
|
[infiniteScrollDistance]="0.5"
|
||||||
|
(scrolled)="onNearOfBottom()"
|
||||||
|
(scrolledUp)="onNearOfTop()"
|
||||||
|
>
|
||||||
<my-video-miniature
|
<my-video-miniature
|
||||||
class="ng-animate"
|
class="ng-animate"
|
||||||
*ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort"
|
*ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort"
|
||||||
>
|
>
|
||||||
</my-video-miniature>
|
</my-video-miniature>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<pagination *ngIf="pagination.totalItems !== null && pagination.totalItems !== 0"
|
|
||||||
[totalItems]="pagination.totalItems" [itemsPerPage]="pagination.itemsPerPage" [maxSize]="6" [boundaryLinks]="true" [rotate]="false"
|
|
||||||
[(ngModel)]="pagination.currentPage" (pageChanged)="onPageChanged($event)"
|
|
||||||
></pagination>
|
|
||||||
|
|
|
@ -19,44 +19,77 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
|
||||||
protected notificationsService: NotificationsService
|
protected notificationsService: NotificationsService
|
||||||
protected router: Router
|
protected router: Router
|
||||||
protected route: ActivatedRoute
|
protected route: ActivatedRoute
|
||||||
|
|
||||||
protected subActivatedRoute: Subscription
|
protected subActivatedRoute: Subscription
|
||||||
|
|
||||||
|
protected abstract currentRoute: string
|
||||||
|
|
||||||
abstract titlePage: string
|
abstract titlePage: string
|
||||||
|
private loadedPages: { [ id: number ]: boolean } = {}
|
||||||
|
|
||||||
abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
|
abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
// Subscribe to route changes
|
// Subscribe to route changes
|
||||||
this.subActivatedRoute = this.route.params.subscribe(routeParams => {
|
const routeParams = this.route.snapshot.params
|
||||||
this.loadRouteParams(routeParams)
|
this.loadRouteParams(routeParams)
|
||||||
|
this.loadMoreVideos('after')
|
||||||
this.getVideos()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
this.subActivatedRoute.unsubscribe()
|
this.subActivatedRoute.unsubscribe()
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideos () {
|
onNearOfTop () {
|
||||||
this.videos = []
|
if (this.pagination.currentPage > 1) {
|
||||||
|
this.previousPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNearOfBottom () {
|
||||||
|
if (this.hasMoreVideos()) {
|
||||||
|
this.nextPage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadMoreVideos (where: 'before' | 'after') {
|
||||||
|
if (this.loadedPages[this.pagination.currentPage] === true) return
|
||||||
|
|
||||||
const observable = this.getVideosObservable()
|
const observable = this.getVideosObservable()
|
||||||
|
|
||||||
observable.subscribe(
|
observable.subscribe(
|
||||||
({ videos, totalVideos }) => {
|
({ videos, totalVideos }) => {
|
||||||
this.videos = videos
|
this.loadedPages[this.pagination.currentPage] = true
|
||||||
this.pagination.totalItems = totalVideos
|
this.pagination.totalItems = totalVideos
|
||||||
|
|
||||||
|
if (where === 'before') {
|
||||||
|
this.videos = videos.concat(this.videos)
|
||||||
|
} else {
|
||||||
|
this.videos = this.videos.concat(videos)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error => this.notificationsService.error('Error', error.text)
|
error => this.notificationsService.error('Error', error.text)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onPageChanged (event: { page: number }) {
|
protected hasMoreVideos () {
|
||||||
// Be sure the current page is set
|
if (!this.pagination.totalItems) return true
|
||||||
this.pagination.currentPage = event.page
|
|
||||||
|
|
||||||
this.navigateToNewParams()
|
const maxPage = this.pagination.totalItems/this.pagination.itemsPerPage
|
||||||
|
return maxPage > this.pagination.currentPage
|
||||||
|
}
|
||||||
|
|
||||||
|
protected previousPage () {
|
||||||
|
this.pagination.currentPage--
|
||||||
|
|
||||||
|
this.setNewRouteParams()
|
||||||
|
this.loadMoreVideos('before')
|
||||||
|
}
|
||||||
|
|
||||||
|
protected nextPage () {
|
||||||
|
this.pagination.currentPage++
|
||||||
|
|
||||||
|
this.setNewRouteParams()
|
||||||
|
this.loadMoreVideos('after')
|
||||||
}
|
}
|
||||||
|
|
||||||
protected buildRouteParams () {
|
protected buildRouteParams () {
|
||||||
|
@ -79,8 +112,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected navigateToNewParams () {
|
protected setNewRouteParams () {
|
||||||
const routeParams = this.buildRouteParams()
|
const routeParams = this.buildRouteParams()
|
||||||
this.router.navigate([ '/videos/list', routeParams ])
|
this.router.navigate([ this.currentRoute, routeParams ])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { AbstractVideoList } from './shared'
|
||||||
})
|
})
|
||||||
export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
|
export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
|
||||||
titlePage = 'Recently added'
|
titlePage = 'Recently added'
|
||||||
|
currentRoute = '/videos/recently-added'
|
||||||
|
|
||||||
constructor (protected router: Router,
|
constructor (protected router: Router,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { AbstractVideoList } from './shared'
|
||||||
})
|
})
|
||||||
export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy {
|
export class VideoTrendingComponent extends AbstractVideoList implements OnInit, OnDestroy {
|
||||||
titlePage = 'Trending'
|
titlePage = 'Trending'
|
||||||
|
currentRoute = '/videos/trending'
|
||||||
|
|
||||||
constructor (protected router: Router,
|
constructor (protected router: Router,
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
|
import { InfiniteScrollModule } from 'ngx-infinite-scroll'
|
||||||
import { SharedModule } from '../shared'
|
import { SharedModule } from '../shared'
|
||||||
import { VideoService } from './shared'
|
import { VideoService } from './shared'
|
||||||
import { MyVideosComponent, VideoMiniatureComponent } from './video-list'
|
import { MyVideosComponent, VideoMiniatureComponent } from './video-list'
|
||||||
|
@ -10,7 +11,8 @@ import { VideosComponent } from './videos.component'
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
VideosRoutingModule,
|
VideosRoutingModule,
|
||||||
SharedModule
|
SharedModule,
|
||||||
|
InfiniteScrollModule
|
||||||
],
|
],
|
||||||
|
|
||||||
declarations: [
|
declarations: [
|
||||||
|
|
|
@ -4714,6 +4714,10 @@ ngx-chips@1.5.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
ng2-material-dropdown "0.7.10"
|
ng2-material-dropdown "0.7.10"
|
||||||
|
|
||||||
|
ngx-infinite-scroll@^0.7.0:
|
||||||
|
version "0.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ngx-infinite-scroll/-/ngx-infinite-scroll-0.7.0.tgz#a390c61c6a05ac14485e1c5bc8b4e6f6bd62fd6a"
|
||||||
|
|
||||||
ngx-pipes@^2.0.5:
|
ngx-pipes@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.0.5.tgz#743b827e350b1e66f5bdae49e90a02fa631d4c54"
|
resolved "https://registry.yarnpkg.com/ngx-pipes/-/ngx-pipes-2.0.5.tgz#743b827e350b1e66f5bdae49e90a02fa631d4c54"
|
||||||
|
|
Loading…
Reference in New Issue