25 items per page
[oweals/peertube.git] / client / src / app / shared / video / abstract-video-list.ts
1 import { OnInit } from '@angular/core'
2 import { ActivatedRoute, Router } from '@angular/router'
3 import { NotificationsService } from 'angular2-notifications'
4 import { Observable } from 'rxjs/Observable'
5 import { AuthService } from '../../core/auth'
6 import { ComponentPagination } from '../rest/component-pagination.model'
7 import { SortField } from './sort-field.type'
8 import { Video } from './video.model'
9
10 export abstract class AbstractVideoList implements OnInit {
11   pagination: ComponentPagination = {
12     currentPage: 1,
13     itemsPerPage: 25,
14     totalItems: null
15   }
16   sort: SortField = '-createdAt'
17   defaultSort: SortField = '-createdAt'
18   videos: Video[] = []
19   loadOnInit = true
20
21   protected abstract notificationsService: NotificationsService
22   protected abstract authService: AuthService
23   protected abstract router: Router
24   protected abstract route: ActivatedRoute
25
26   protected abstract currentRoute: string
27
28   abstract titlePage: string
29
30   protected otherParams = {}
31
32   private loadedPages: { [ id: number ]: boolean } = {}
33
34   abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
35
36   get user () {
37     return this.authService.getUser()
38   }
39
40   ngOnInit () {
41     // Subscribe to route changes
42     const routeParams = this.route.snapshot.params
43     this.loadRouteParams(routeParams)
44
45     if (this.loadOnInit === true) this.loadMoreVideos('after')
46   }
47
48   onNearOfTop () {
49     if (this.pagination.currentPage > 1) {
50       this.previousPage()
51     }
52   }
53
54   onNearOfBottom () {
55     if (this.hasMoreVideos()) {
56       this.nextPage()
57     }
58   }
59
60   reloadVideos () {
61     this.videos = []
62     this.loadedPages = {}
63     this.loadMoreVideos('before')
64   }
65
66   loadMoreVideos (where: 'before' | 'after') {
67     if (this.loadedPages[this.pagination.currentPage] === true) return
68
69     const observable = this.getVideosObservable()
70
71     observable.subscribe(
72       ({ videos, totalVideos }) => {
73         // Paging is too high, return to the first one
74         if (this.pagination.currentPage > 1 && totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) {
75           this.pagination.currentPage = 1
76           this.setNewRouteParams()
77           return this.reloadVideos()
78         }
79
80         this.loadedPages[this.pagination.currentPage] = true
81         this.pagination.totalItems = totalVideos
82
83         if (where === 'before') {
84           this.videos = videos.concat(this.videos)
85         } else {
86           this.videos = this.videos.concat(videos)
87         }
88       },
89       error => this.notificationsService.error('Error', error.message)
90     )
91   }
92
93   protected hasMoreVideos () {
94     // No results
95     if (this.pagination.totalItems === 0) return false
96
97     // Not loaded yet
98     if (!this.pagination.totalItems) return true
99
100     const maxPage = this.pagination.totalItems / this.pagination.itemsPerPage
101     return maxPage > this.pagination.currentPage
102   }
103
104   protected previousPage () {
105     this.pagination.currentPage--
106
107     this.setNewRouteParams()
108     this.loadMoreVideos('before')
109   }
110
111   protected nextPage () {
112     this.pagination.currentPage++
113
114     this.setNewRouteParams()
115     this.loadMoreVideos('after')
116   }
117
118   protected buildRouteParams () {
119     // There is always a sort and a current page
120     const params = {
121       sort: this.sort,
122       page: this.pagination.currentPage
123     }
124
125     return Object.assign(params, this.otherParams)
126   }
127
128   protected loadRouteParams (routeParams: { [ key: string ]: any }) {
129     this.sort = routeParams['sort'] as SortField || this.defaultSort
130
131     if (routeParams['page'] !== undefined) {
132       this.pagination.currentPage = parseInt(routeParams['page'], 10)
133     } else {
134       this.pagination.currentPage = 1
135     }
136   }
137
138   protected setNewRouteParams () {
139     const routeParams = this.buildRouteParams()
140     this.router.navigate([ this.currentRoute, routeParams ])
141   }
142 }