Add likes/dislikes bar
[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 { SortField } from './sort-field.type'
6 import { VideoPagination } from './video-pagination.model'
7 import { Video } from './video.model'
8
9 export abstract class AbstractVideoList implements OnInit {
10   pagination: VideoPagination = {
11     currentPage: 1,
12     itemsPerPage: 25,
13     totalItems: null
14   }
15   sort: SortField = '-createdAt'
16   defaultSort: SortField = '-createdAt'
17   videos: Video[] = []
18   loadOnInit = true
19
20   protected notificationsService: NotificationsService
21   protected router: Router
22   protected route: ActivatedRoute
23
24   protected abstract currentRoute: string
25
26   abstract titlePage: string
27   private loadedPages: { [ id: number ]: boolean } = {}
28
29   abstract getVideosObservable (): Observable<{ videos: Video[], totalVideos: number}>
30
31   ngOnInit () {
32     // Subscribe to route changes
33     const routeParams = this.route.snapshot.params
34     this.loadRouteParams(routeParams)
35
36     if (this.loadOnInit === true) this.loadMoreVideos('after')
37   }
38
39   onNearOfTop () {
40     if (this.pagination.currentPage > 1) {
41       this.previousPage()
42     }
43   }
44
45   onNearOfBottom () {
46     if (this.hasMoreVideos()) {
47       this.nextPage()
48     }
49   }
50
51   reloadVideos () {
52     this.videos = []
53     this.loadedPages = {}
54     this.loadMoreVideos('before')
55   }
56
57   loadMoreVideos (where: 'before' | 'after') {
58     if (this.loadedPages[this.pagination.currentPage] === true) return
59
60     const observable = this.getVideosObservable()
61
62     observable.subscribe(
63       ({ videos, totalVideos }) => {
64         // Paging is too high, return to the first one
65         if (totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) {
66           this.pagination.currentPage = 1
67           this.setNewRouteParams()
68           return this.reloadVideos()
69         }
70
71         this.loadedPages[this.pagination.currentPage] = true
72         this.pagination.totalItems = totalVideos
73
74         if (where === 'before') {
75           this.videos = videos.concat(this.videos)
76         } else {
77           this.videos = this.videos.concat(videos)
78         }
79       },
80       error => this.notificationsService.error('Error', error.text)
81     )
82   }
83
84   protected hasMoreVideos () {
85     if (!this.pagination.totalItems) return true
86
87     const maxPage = this.pagination.totalItems / this.pagination.itemsPerPage
88     return maxPage > this.pagination.currentPage
89   }
90
91   protected previousPage () {
92     this.pagination.currentPage--
93
94     this.setNewRouteParams()
95     this.loadMoreVideos('before')
96   }
97
98   protected nextPage () {
99     this.pagination.currentPage++
100
101     this.setNewRouteParams()
102     this.loadMoreVideos('after')
103   }
104
105   protected buildRouteParams () {
106     // There is always a sort and a current page
107     const params = {
108       sort: this.sort,
109       page: this.pagination.currentPage
110     }
111
112     return params
113   }
114
115   protected loadRouteParams (routeParams: { [ key: string ]: any }) {
116     this.sort = routeParams['sort'] as SortField || this.defaultSort
117
118     if (routeParams['page'] !== undefined) {
119       this.pagination.currentPage = parseInt(routeParams['page'], 10)
120     } else {
121       this.pagination.currentPage = 1
122     }
123   }
124
125   protected setNewRouteParams () {
126     const routeParams = this.buildRouteParams()
127     this.router.navigate([ this.currentRoute, routeParams ])
128   }
129 }