Add pagination support to the client
This commit is contained in:
parent
46246b5f19
commit
322940742b
|
@ -5,7 +5,7 @@
|
||||||
<h4>PeerTube</h4>
|
<h4>PeerTube</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-md-9">
|
||||||
<input
|
<input
|
||||||
type="text" id="search_video" name="search_video" class="form-control" placeholder="Search a video..."
|
type="text" id="search_video" name="search_video" class="form-control" placeholder="Search a video..."
|
||||||
#search (keyup.enter)="doSearch(search.value)"
|
#search (keyup.enter)="doSearch(search.value)"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="video-miniature" (mouseenter)="onHover()" (mouseleave)="onBlur()">
|
<div class="video-miniature col-md-4" (mouseenter)="onHover()" (mouseleave)="onBlur()">
|
||||||
<a
|
<a
|
||||||
[routerLink]="['VideosWatch', { id: video.id }]" [attr.title]="video.description"
|
[routerLink]="['VideosWatch', { id: video.id }]" [attr.title]="video.description"
|
||||||
class="video-miniature-thumbnail"
|
class="video-miniature-thumbnail"
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
.video-miniature {
|
.video-miniature {
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
height: 200px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 40px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.video-miniature-thumbnail {
|
.video-miniature-thumbnail {
|
||||||
|
@ -11,7 +9,7 @@
|
||||||
|
|
||||||
.video-miniature-duration {
|
.video-miniature-duration {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 2px;
|
right: 60px;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
@ -24,7 +22,7 @@
|
||||||
.video-miniature-remove {
|
.video-miniature-remove {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 2px;
|
left: 16px;
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.8);
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
<div *ngIf="videos.length === 0">There is no video.</div>
|
<div class="videos-miniatures">
|
||||||
<my-video-miniature *ngFor="let video of videos" [video]="video" [user]="user" (removed)="onRemoved(video)">
|
<div *ngIf="videos.length === 0">There is no video.</div>
|
||||||
</my-video-miniature>
|
|
||||||
|
<my-video-miniature *ngFor="let video of videos" [video]="video" [user]="user" (removed)="onRemoved(video)">
|
||||||
|
</my-video-miniature>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
[totalItems]="pagination.total" [itemsPerPage]="pagination.itemsPerPage" [(ngModel)]="pagination.currentPage"
|
||||||
|
(ngModelChange)="getVideos()"
|
||||||
|
></pagination>
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
.loading {
|
.videos-miniatures {
|
||||||
display: inline-block;
|
min-height: 600px;
|
||||||
margin-top: 100px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my-videos-miniature {
|
my-videos-miniature {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pagination {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { ROUTER_DIRECTIVES, RouteParams } from '@angular/router-deprecated';
|
import { ROUTER_DIRECTIVES, RouteParams } from '@angular/router-deprecated';
|
||||||
|
|
||||||
|
import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination';
|
||||||
|
|
||||||
import { AuthService } from '../../../users/services/auth.service';
|
import { AuthService } from '../../../users/services/auth.service';
|
||||||
|
import { Pagination } from '../../pagination';
|
||||||
import { User } from '../../../users/models/user';
|
import { User } from '../../../users/models/user';
|
||||||
import { VideosService } from '../../videos.service';
|
import { VideosService } from '../../videos.service';
|
||||||
import { Video } from '../../video';
|
import { Video } from '../../video';
|
||||||
|
@ -11,21 +14,26 @@ import { VideoMiniatureComponent } from './video-miniature.component';
|
||||||
selector: 'my-videos-list',
|
selector: 'my-videos-list',
|
||||||
styleUrls: [ 'app/angular/videos/components/list/videos-list.component.css' ],
|
styleUrls: [ 'app/angular/videos/components/list/videos-list.component.css' ],
|
||||||
templateUrl: 'app/angular/videos/components/list/videos-list.component.html',
|
templateUrl: 'app/angular/videos/components/list/videos-list.component.html',
|
||||||
directives: [ ROUTER_DIRECTIVES, VideoMiniatureComponent ]
|
directives: [ ROUTER_DIRECTIVES, PAGINATION_DIRECTIVES, VideoMiniatureComponent ]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class VideosListComponent implements OnInit {
|
export class VideosListComponent implements OnInit {
|
||||||
user: User = null;
|
user: User = null;
|
||||||
videos: Video[] = [];
|
videos: Video[] = [];
|
||||||
|
pagination: Pagination = {
|
||||||
|
currentPage: 1,
|
||||||
|
itemsPerPage: 9,
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
|
||||||
private search: string;
|
private search: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _authService: AuthService,
|
private _authService: AuthService,
|
||||||
private _videosService: VideosService,
|
private _videosService: VideosService,
|
||||||
routeParams: RouteParams
|
private _routeParams: RouteParams
|
||||||
) {
|
) {
|
||||||
this.search = routeParams.get('search');
|
this.search = this._routeParams.get('search');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -40,13 +48,16 @@ export class VideosListComponent implements OnInit {
|
||||||
let observable = null;
|
let observable = null;
|
||||||
|
|
||||||
if (this.search !== null) {
|
if (this.search !== null) {
|
||||||
observable = this._videosService.searchVideos(this.search);
|
observable = this._videosService.searchVideos(this.search, this.pagination);
|
||||||
} else {
|
} else {
|
||||||
observable = this._videosService.getVideos();
|
observable = this._videosService.getVideos(this.pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
observable.subscribe(
|
observable.subscribe(
|
||||||
videos => this.videos = videos,
|
({ videos, totalVideos }) => {
|
||||||
|
this.videos = videos;
|
||||||
|
this.pagination.total = totalVideos;
|
||||||
|
},
|
||||||
error => alert(error)
|
error => alert(error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Pagination {
|
||||||
|
currentPage: number;
|
||||||
|
itemsPerPage: number;
|
||||||
|
total: number;
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Http, Response } from '@angular/http';
|
import { Http, Response, RequestOptions, URLSearchParams } from '@angular/http';
|
||||||
import { Observable } from 'rxjs/Rx';
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
|
||||||
|
import { Pagination } from './pagination';
|
||||||
import { Video } from './video';
|
import { Video } from './video';
|
||||||
import { AuthService } from '../users/services/auth.service';
|
import { AuthService } from '../users/services/auth.service';
|
||||||
|
|
||||||
|
@ -11,8 +12,9 @@ export class VideosService {
|
||||||
|
|
||||||
constructor (private http: Http, private _authService: AuthService) {}
|
constructor (private http: Http, private _authService: AuthService) {}
|
||||||
|
|
||||||
getVideos() {
|
getVideos(pagination: Pagination) {
|
||||||
return this.http.get(this._baseVideoUrl)
|
const params = { search: this.createPaginationParams(pagination) };
|
||||||
|
return this.http.get(this._baseVideoUrl, params)
|
||||||
.map(res => res.json())
|
.map(res => res.json())
|
||||||
.map(this.extractVideos)
|
.map(this.extractVideos)
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
|
@ -31,24 +33,38 @@ export class VideosService {
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
searchVideos(search: string) {
|
searchVideos(search: string, pagination: Pagination) {
|
||||||
return this.http.get(this._baseVideoUrl + 'search/' + search)
|
const params = { search: this.createPaginationParams(pagination) };
|
||||||
|
return this.http.get(this._baseVideoUrl + 'search/' + encodeURIComponent(search), params)
|
||||||
.map(res => res.json())
|
.map(res => res.json())
|
||||||
.map(this.extractVideos)
|
.map(this.extractVideos)
|
||||||
.catch(this.handleError);
|
.catch(this.handleError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractVideos (body: any[]) {
|
private extractVideos (body: any) {
|
||||||
|
const videos_json = body.data;
|
||||||
|
const totalVideos = body.total;
|
||||||
const videos = [];
|
const videos = [];
|
||||||
for (const video_json of body) {
|
for (const video_json of videos_json) {
|
||||||
videos.push(new Video(video_json));
|
videos.push(new Video(video_json));
|
||||||
}
|
}
|
||||||
|
|
||||||
return videos;
|
return { videos, totalVideos };
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleError (error: Response) {
|
private handleError (error: Response) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return Observable.throw(error.json().error || 'Server error');
|
return Observable.throw(error.json().error || 'Server error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private createPaginationParams(pagination: Pagination) {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage;
|
||||||
|
const count: number = pagination.itemsPerPage;
|
||||||
|
|
||||||
|
params.set('start', start.toString());
|
||||||
|
params.set('count', count.toString());
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,21 @@
|
||||||
},
|
},
|
||||||
"license": "GPLv3",
|
"license": "GPLv3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"angular-pipes": "^2.0.0",
|
|
||||||
"@angular/common": "2.0.0-rc.1",
|
"@angular/common": "2.0.0-rc.1",
|
||||||
"@angular/compiler": "2.0.0-rc.1",
|
"@angular/compiler": "2.0.0-rc.1",
|
||||||
"@angular/core": "2.0.0-rc.1",
|
"@angular/core": "2.0.0-rc.1",
|
||||||
"@angular/http": "2.0.0-rc.1",
|
"@angular/http": "2.0.0-rc.1",
|
||||||
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
|
|
||||||
"@angular/platform-browser": "2.0.0-rc.1",
|
"@angular/platform-browser": "2.0.0-rc.1",
|
||||||
|
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
|
||||||
"@angular/router-deprecated": "2.0.0-rc.1",
|
"@angular/router-deprecated": "2.0.0-rc.1",
|
||||||
|
"angular-pipes": "^2.0.0",
|
||||||
"blueimp-file-upload": "^9.12.1",
|
"blueimp-file-upload": "^9.12.1",
|
||||||
"bootstrap-sass": "^3.3.6",
|
"bootstrap-sass": "^3.3.6",
|
||||||
"es6-promise": "^3.0.2",
|
"es6-promise": "^3.0.2",
|
||||||
"es6-shim": "^0.35.0",
|
"es6-shim": "^0.35.0",
|
||||||
"jquery": "^2.2.3",
|
"jquery": "^2.2.3",
|
||||||
"jquery.ui.widget": "^1.10.3",
|
"jquery.ui.widget": "^1.10.3",
|
||||||
|
"ng2-bootstrap": "^1.0.16",
|
||||||
"reflect-metadata": "0.1.3",
|
"reflect-metadata": "0.1.3",
|
||||||
"rxjs": "5.0.0-beta.6",
|
"rxjs": "5.0.0-beta.6",
|
||||||
"systemjs": "0.19.27",
|
"systemjs": "0.19.27",
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
var map = {
|
var map = {
|
||||||
'app': 'app/angular',
|
'app': 'app/angular',
|
||||||
'angular-pipes': 'app/node_modules/angular-pipes',
|
'angular-pipes': 'app/node_modules/angular-pipes',
|
||||||
|
'ng2-bootstrap': 'app/node_modules/ng2-bootstrap',
|
||||||
'angular-rxjs.bundle': 'app/bundles/angular-rxjs.bundle.js'
|
'angular-rxjs.bundle': 'app/bundles/angular-rxjs.bundle.js'
|
||||||
}
|
}
|
||||||
|
|
||||||
var packages = {
|
var packages = {
|
||||||
'app': { main: 'main.js', defaultExtension: 'js' },
|
'app': { main: 'main.js', defaultExtension: 'js' },
|
||||||
|
'ng2-bootstrap': { defaultExtension: 'js' },
|
||||||
'rxjs': { defaultExtension: 'js' }
|
'rxjs': { defaultExtension: 'js' }
|
||||||
}
|
}
|
||||||
var packageNames = [
|
var packageNames = [
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"angular/videos/components/list/video-miniature.component.ts",
|
"angular/videos/components/list/video-miniature.component.ts",
|
||||||
"angular/videos/components/list/videos-list.component.ts",
|
"angular/videos/components/list/videos-list.component.ts",
|
||||||
"angular/videos/components/watch/videos-watch.component.ts",
|
"angular/videos/components/watch/videos-watch.component.ts",
|
||||||
|
"angular/videos/pagination.ts",
|
||||||
"angular/videos/video.ts",
|
"angular/videos/video.ts",
|
||||||
"angular/videos/videos.service.ts",
|
"angular/videos/videos.service.ts",
|
||||||
"typings/globals/es6-shim/index.d.ts",
|
"typings/globals/es6-shim/index.d.ts",
|
||||||
|
|
Loading…
Reference in New Issue