diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-05-22 10:43:06 +0200 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-05-22 10:44:35 +0200 |
commit | 322940742b4dca168de6dfed0d1ebf5926dab528 (patch) | |
tree | 7b7fdb77595aa7d6a89d1045ab6012a9e1d68aab | |
parent | 46246b5f194caafba4e3a72e9365acd8b35785de (diff) | |
download | PeerTube-322940742b4dca168de6dfed0d1ebf5926dab528.tar.gz PeerTube-322940742b4dca168de6dfed0d1ebf5926dab528.tar.zst PeerTube-322940742b4dca168de6dfed0d1ebf5926dab528.zip |
Add pagination support to the client
-rw-r--r-- | client/angular/app/app.component.html | 2 | ||||
-rw-r--r-- | client/angular/videos/components/list/video-miniature.component.html | 2 | ||||
-rw-r--r-- | client/angular/videos/components/list/video-miniature.component.scss | 6 | ||||
-rw-r--r-- | client/angular/videos/components/list/videos-list.component.html | 14 | ||||
-rw-r--r-- | client/angular/videos/components/list/videos-list.component.scss | 10 | ||||
-rw-r--r-- | client/angular/videos/components/list/videos-list.component.ts | 23 | ||||
-rw-r--r-- | client/angular/videos/pagination.ts | 5 | ||||
-rw-r--r-- | client/angular/videos/videos.service.ts | 32 | ||||
-rw-r--r-- | client/package.json | 5 | ||||
-rw-r--r-- | client/systemjs.config.js | 2 | ||||
-rw-r--r-- | client/tsconfig.json | 1 |
11 files changed, 74 insertions, 28 deletions
diff --git a/client/angular/app/app.component.html b/client/angular/app/app.component.html index 949b375d2..ccbaef947 100644 --- a/client/angular/app/app.component.html +++ b/client/angular/app/app.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | <h4>PeerTube</h4> | 5 | <h4>PeerTube</h4> |
6 | </div> | 6 | </div> |
7 | 7 | ||
8 | <div class="col-md-8"> | 8 | <div class="col-md-9"> |
9 | <input | 9 | <input |
10 | type="text" id="search_video" name="search_video" class="form-control" placeholder="Search a video..." | 10 | type="text" id="search_video" name="search_video" class="form-control" placeholder="Search a video..." |
11 | #search (keyup.enter)="doSearch(search.value)" | 11 | #search (keyup.enter)="doSearch(search.value)" |
diff --git a/client/angular/videos/components/list/video-miniature.component.html b/client/angular/videos/components/list/video-miniature.component.html index b88a19d5e..244254b5a 100644 --- a/client/angular/videos/components/list/video-miniature.component.html +++ b/client/angular/videos/components/list/video-miniature.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="video-miniature" (mouseenter)="onHover()" (mouseleave)="onBlur()"> | 1 | <div class="video-miniature col-md-4" (mouseenter)="onHover()" (mouseleave)="onBlur()"> |
2 | <a | 2 | <a |
3 | [routerLink]="['VideosWatch', { id: video.id }]" [attr.title]="video.description" | 3 | [routerLink]="['VideosWatch', { id: video.id }]" [attr.title]="video.description" |
4 | class="video-miniature-thumbnail" | 4 | class="video-miniature-thumbnail" |
diff --git a/client/angular/videos/components/list/video-miniature.component.scss b/client/angular/videos/components/list/video-miniature.component.scss index dbcd65820..4488abe22 100644 --- a/client/angular/videos/components/list/video-miniature.component.scss +++ b/client/angular/videos/components/list/video-miniature.component.scss | |||
@@ -1,8 +1,6 @@ | |||
1 | .video-miniature { | 1 | .video-miniature { |
2 | width: 200px; | ||
3 | height: 200px; | 2 | height: 200px; |
4 | display: inline-block; | 3 | display: inline-block; |
5 | margin-right: 40px; | ||
6 | position: relative; | 4 | position: relative; |
7 | 5 | ||
8 | .video-miniature-thumbnail { | 6 | .video-miniature-thumbnail { |
@@ -11,7 +9,7 @@ | |||
11 | 9 | ||
12 | .video-miniature-duration { | 10 | .video-miniature-duration { |
13 | position: absolute; | 11 | position: absolute; |
14 | right: 2px; | 12 | right: 60px; |
15 | bottom: 2px; | 13 | bottom: 2px; |
16 | display: inline-block; | 14 | display: inline-block; |
17 | background-color: rgba(0, 0, 0, 0.8); | 15 | background-color: rgba(0, 0, 0, 0.8); |
@@ -24,7 +22,7 @@ | |||
24 | .video-miniature-remove { | 22 | .video-miniature-remove { |
25 | display: inline-block; | 23 | display: inline-block; |
26 | position: absolute; | 24 | position: absolute; |
27 | left: 2px; | 25 | left: 16px; |
28 | background-color: rgba(0, 0, 0, 0.8); | 26 | background-color: rgba(0, 0, 0, 0.8); |
29 | color: rgba(255, 255, 255, 0.8); | 27 | color: rgba(255, 255, 255, 0.8); |
30 | padding: 2px; | 28 | padding: 2px; |
diff --git a/client/angular/videos/components/list/videos-list.component.html b/client/angular/videos/components/list/videos-list.component.html index 776339d10..39cdf29ba 100644 --- a/client/angular/videos/components/list/videos-list.component.html +++ b/client/angular/videos/components/list/videos-list.component.html | |||
@@ -1,3 +1,11 @@ | |||
1 | <div *ngIf="videos.length === 0">There is no video.</div> | 1 | <div class="videos-miniatures"> |
2 | <my-video-miniature *ngFor="let video of videos" [video]="video" [user]="user" (removed)="onRemoved(video)"> | 2 | <div *ngIf="videos.length === 0">There is no video.</div> |
3 | </my-video-miniature> | 3 | |
4 | <my-video-miniature *ngFor="let video of videos" [video]="video" [user]="user" (removed)="onRemoved(video)"> | ||
5 | </my-video-miniature> | ||
6 | </div> | ||
7 | |||
8 | <pagination | ||
9 | [totalItems]="pagination.total" [itemsPerPage]="pagination.itemsPerPage" [(ngModel)]="pagination.currentPage" | ||
10 | (ngModelChange)="getVideos()" | ||
11 | ></pagination> | ||
diff --git a/client/angular/videos/components/list/videos-list.component.scss b/client/angular/videos/components/list/videos-list.component.scss index ac930978c..05c38b833 100644 --- a/client/angular/videos/components/list/videos-list.component.scss +++ b/client/angular/videos/components/list/videos-list.component.scss | |||
@@ -1,8 +1,12 @@ | |||
1 | .loading { | 1 | .videos-miniatures { |
2 | display: inline-block; | 2 | min-height: 600px; |
3 | margin-top: 100px; | ||
4 | } | 3 | } |
5 | 4 | ||
6 | my-videos-miniature { | 5 | my-videos-miniature { |
7 | display: inline-block; | 6 | display: inline-block; |
8 | } | 7 | } |
8 | |||
9 | pagination { | ||
10 | display: block; | ||
11 | text-align: center; | ||
12 | } | ||
diff --git a/client/angular/videos/components/list/videos-list.component.ts b/client/angular/videos/components/list/videos-list.component.ts index 6fc0c1f04..341afdaa6 100644 --- a/client/angular/videos/components/list/videos-list.component.ts +++ b/client/angular/videos/components/list/videos-list.component.ts | |||
@@ -1,7 +1,10 @@ | |||
1 | import { Component, OnInit } from '@angular/core'; | 1 | import { Component, OnInit } from '@angular/core'; |
2 | import { ROUTER_DIRECTIVES, RouteParams } from '@angular/router-deprecated'; | 2 | import { ROUTER_DIRECTIVES, RouteParams } from '@angular/router-deprecated'; |
3 | 3 | ||
4 | import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination'; | ||
5 | |||
4 | import { AuthService } from '../../../users/services/auth.service'; | 6 | import { AuthService } from '../../../users/services/auth.service'; |
7 | import { Pagination } from '../../pagination'; | ||
5 | import { User } from '../../../users/models/user'; | 8 | import { User } from '../../../users/models/user'; |
6 | import { VideosService } from '../../videos.service'; | 9 | import { VideosService } from '../../videos.service'; |
7 | import { Video } from '../../video'; | 10 | import { Video } from '../../video'; |
@@ -11,21 +14,26 @@ import { VideoMiniatureComponent } from './video-miniature.component'; | |||
11 | selector: 'my-videos-list', | 14 | selector: 'my-videos-list', |
12 | styleUrls: [ 'app/angular/videos/components/list/videos-list.component.css' ], | 15 | styleUrls: [ 'app/angular/videos/components/list/videos-list.component.css' ], |
13 | templateUrl: 'app/angular/videos/components/list/videos-list.component.html', | 16 | templateUrl: 'app/angular/videos/components/list/videos-list.component.html', |
14 | directives: [ ROUTER_DIRECTIVES, VideoMiniatureComponent ] | 17 | directives: [ ROUTER_DIRECTIVES, PAGINATION_DIRECTIVES, VideoMiniatureComponent ] |
15 | }) | 18 | }) |
16 | 19 | ||
17 | export class VideosListComponent implements OnInit { | 20 | export class VideosListComponent implements OnInit { |
18 | user: User = null; | 21 | user: User = null; |
19 | videos: Video[] = []; | 22 | videos: Video[] = []; |
23 | pagination: Pagination = { | ||
24 | currentPage: 1, | ||
25 | itemsPerPage: 9, | ||
26 | total: 0 | ||
27 | } | ||
20 | 28 | ||
21 | private search: string; | 29 | private search: string; |
22 | 30 | ||
23 | constructor( | 31 | constructor( |
24 | private _authService: AuthService, | 32 | private _authService: AuthService, |
25 | private _videosService: VideosService, | 33 | private _videosService: VideosService, |
26 | routeParams: RouteParams | 34 | private _routeParams: RouteParams |
27 | ) { | 35 | ) { |
28 | this.search = routeParams.get('search'); | 36 | this.search = this._routeParams.get('search'); |
29 | } | 37 | } |
30 | 38 | ||
31 | ngOnInit() { | 39 | ngOnInit() { |
@@ -40,13 +48,16 @@ export class VideosListComponent implements OnInit { | |||
40 | let observable = null; | 48 | let observable = null; |
41 | 49 | ||
42 | if (this.search !== null) { | 50 | if (this.search !== null) { |
43 | observable = this._videosService.searchVideos(this.search); | 51 | observable = this._videosService.searchVideos(this.search, this.pagination); |
44 | } else { | 52 | } else { |
45 | observable = this._videosService.getVideos(); | 53 | observable = this._videosService.getVideos(this.pagination); |
46 | } | 54 | } |
47 | 55 | ||
48 | observable.subscribe( | 56 | observable.subscribe( |
49 | videos => this.videos = videos, | 57 | ({ videos, totalVideos }) => { |
58 | this.videos = videos; | ||
59 | this.pagination.total = totalVideos; | ||
60 | }, | ||
50 | error => alert(error) | 61 | error => alert(error) |
51 | ); | 62 | ); |
52 | } | 63 | } |
diff --git a/client/angular/videos/pagination.ts b/client/angular/videos/pagination.ts new file mode 100644 index 000000000..06f7a7875 --- /dev/null +++ b/client/angular/videos/pagination.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export interface Pagination { | ||
2 | currentPage: number; | ||
3 | itemsPerPage: number; | ||
4 | total: number; | ||
5 | } | ||
diff --git a/client/angular/videos/videos.service.ts b/client/angular/videos/videos.service.ts index f4790b511..94ef418eb 100644 --- a/client/angular/videos/videos.service.ts +++ b/client/angular/videos/videos.service.ts | |||
@@ -1,7 +1,8 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core'; |
2 | import { Http, Response } from '@angular/http'; | 2 | import { Http, Response, RequestOptions, URLSearchParams } from '@angular/http'; |
3 | import { Observable } from 'rxjs/Rx'; | 3 | import { Observable } from 'rxjs/Rx'; |
4 | 4 | ||
5 | import { Pagination } from './pagination'; | ||
5 | import { Video } from './video'; | 6 | import { Video } from './video'; |
6 | import { AuthService } from '../users/services/auth.service'; | 7 | import { AuthService } from '../users/services/auth.service'; |
7 | 8 | ||
@@ -11,8 +12,9 @@ export class VideosService { | |||
11 | 12 | ||
12 | constructor (private http: Http, private _authService: AuthService) {} | 13 | constructor (private http: Http, private _authService: AuthService) {} |
13 | 14 | ||
14 | getVideos() { | 15 | getVideos(pagination: Pagination) { |
15 | return this.http.get(this._baseVideoUrl) | 16 | const params = { search: this.createPaginationParams(pagination) }; |
17 | return this.http.get(this._baseVideoUrl, params) | ||
16 | .map(res => res.json()) | 18 | .map(res => res.json()) |
17 | .map(this.extractVideos) | 19 | .map(this.extractVideos) |
18 | .catch(this.handleError); | 20 | .catch(this.handleError); |
@@ -31,24 +33,38 @@ export class VideosService { | |||
31 | .catch(this.handleError); | 33 | .catch(this.handleError); |
32 | } | 34 | } |
33 | 35 | ||
34 | searchVideos(search: string) { | 36 | searchVideos(search: string, pagination: Pagination) { |
35 | return this.http.get(this._baseVideoUrl + 'search/' + search) | 37 | const params = { search: this.createPaginationParams(pagination) }; |
38 | return this.http.get(this._baseVideoUrl + 'search/' + encodeURIComponent(search), params) | ||
36 | .map(res => res.json()) | 39 | .map(res => res.json()) |
37 | .map(this.extractVideos) | 40 | .map(this.extractVideos) |
38 | .catch(this.handleError); | 41 | .catch(this.handleError); |
39 | } | 42 | } |
40 | 43 | ||
41 | private extractVideos (body: any[]) { | 44 | private extractVideos (body: any) { |
45 | const videos_json = body.data; | ||
46 | const totalVideos = body.total; | ||
42 | const videos = []; | 47 | const videos = []; |
43 | for (const video_json of body) { | 48 | for (const video_json of videos_json) { |
44 | videos.push(new Video(video_json)); | 49 | videos.push(new Video(video_json)); |
45 | } | 50 | } |
46 | 51 | ||
47 | return videos; | 52 | return { videos, totalVideos }; |
48 | } | 53 | } |
49 | 54 | ||
50 | private handleError (error: Response) { | 55 | private handleError (error: Response) { |
51 | console.error(error); | 56 | console.error(error); |
52 | return Observable.throw(error.json().error || 'Server error'); | 57 | return Observable.throw(error.json().error || 'Server error'); |
53 | } | 58 | } |
59 | |||
60 | private createPaginationParams(pagination: Pagination) { | ||
61 | const params = new URLSearchParams(); | ||
62 | const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage; | ||
63 | const count: number = pagination.itemsPerPage; | ||
64 | |||
65 | params.set('start', start.toString()); | ||
66 | params.set('count', count.toString()); | ||
67 | |||
68 | return params; | ||
69 | } | ||
54 | } | 70 | } |
diff --git a/client/package.json b/client/package.json index b730a1f4a..b77c6e447 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -21,20 +21,21 @@ | |||
21 | }, | 21 | }, |
22 | "license": "GPLv3", | 22 | "license": "GPLv3", |
23 | "dependencies": { | 23 | "dependencies": { |
24 | "angular-pipes": "^2.0.0", | ||
25 | "@angular/common": "2.0.0-rc.1", | 24 | "@angular/common": "2.0.0-rc.1", |
26 | "@angular/compiler": "2.0.0-rc.1", | 25 | "@angular/compiler": "2.0.0-rc.1", |
27 | "@angular/core": "2.0.0-rc.1", | 26 | "@angular/core": "2.0.0-rc.1", |
28 | "@angular/http": "2.0.0-rc.1", | 27 | "@angular/http": "2.0.0-rc.1", |
29 | "@angular/platform-browser-dynamic": "2.0.0-rc.1", | ||
30 | "@angular/platform-browser": "2.0.0-rc.1", | 28 | "@angular/platform-browser": "2.0.0-rc.1", |
29 | "@angular/platform-browser-dynamic": "2.0.0-rc.1", | ||
31 | "@angular/router-deprecated": "2.0.0-rc.1", | 30 | "@angular/router-deprecated": "2.0.0-rc.1", |
31 | "angular-pipes": "^2.0.0", | ||
32 | "blueimp-file-upload": "^9.12.1", | 32 | "blueimp-file-upload": "^9.12.1", |
33 | "bootstrap-sass": "^3.3.6", | 33 | "bootstrap-sass": "^3.3.6", |
34 | "es6-promise": "^3.0.2", | 34 | "es6-promise": "^3.0.2", |
35 | "es6-shim": "^0.35.0", | 35 | "es6-shim": "^0.35.0", |
36 | "jquery": "^2.2.3", | 36 | "jquery": "^2.2.3", |
37 | "jquery.ui.widget": "^1.10.3", | 37 | "jquery.ui.widget": "^1.10.3", |
38 | "ng2-bootstrap": "^1.0.16", | ||
38 | "reflect-metadata": "0.1.3", | 39 | "reflect-metadata": "0.1.3", |
39 | "rxjs": "5.0.0-beta.6", | 40 | "rxjs": "5.0.0-beta.6", |
40 | "systemjs": "0.19.27", | 41 | "systemjs": "0.19.27", |
diff --git a/client/systemjs.config.js b/client/systemjs.config.js index 0ac94ca44..82ca5bb70 100644 --- a/client/systemjs.config.js +++ b/client/systemjs.config.js | |||
@@ -2,11 +2,13 @@ | |||
2 | var map = { | 2 | var map = { |
3 | 'app': 'app/angular', | 3 | 'app': 'app/angular', |
4 | 'angular-pipes': 'app/node_modules/angular-pipes', | 4 | 'angular-pipes': 'app/node_modules/angular-pipes', |
5 | 'ng2-bootstrap': 'app/node_modules/ng2-bootstrap', | ||
5 | 'angular-rxjs.bundle': 'app/bundles/angular-rxjs.bundle.js' | 6 | 'angular-rxjs.bundle': 'app/bundles/angular-rxjs.bundle.js' |
6 | } | 7 | } |
7 | 8 | ||
8 | var packages = { | 9 | var packages = { |
9 | 'app': { main: 'main.js', defaultExtension: 'js' }, | 10 | 'app': { main: 'main.js', defaultExtension: 'js' }, |
11 | 'ng2-bootstrap': { defaultExtension: 'js' }, | ||
10 | 'rxjs': { defaultExtension: 'js' } | 12 | 'rxjs': { defaultExtension: 'js' } |
11 | } | 13 | } |
12 | var packageNames = [ | 14 | var packageNames = [ |
diff --git a/client/tsconfig.json b/client/tsconfig.json index fac9da116..1d002f7b0 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json | |||
@@ -32,6 +32,7 @@ | |||
32 | "angular/videos/components/list/video-miniature.component.ts", | 32 | "angular/videos/components/list/video-miniature.component.ts", |
33 | "angular/videos/components/list/videos-list.component.ts", | 33 | "angular/videos/components/list/videos-list.component.ts", |
34 | "angular/videos/components/watch/videos-watch.component.ts", | 34 | "angular/videos/components/watch/videos-watch.component.ts", |
35 | "angular/videos/pagination.ts", | ||
35 | "angular/videos/video.ts", | 36 | "angular/videos/video.ts", |
36 | "angular/videos/videos.service.ts", | 37 | "angular/videos/videos.service.ts", |
37 | "typings/globals/es6-shim/index.d.ts", | 38 | "typings/globals/es6-shim/index.d.ts", |