export * from './shared';
-export * from './video-add';
+export * from './video-edit';
export * from './video-list';
export * from './video-watch';
export * from './videos-routing.module';
by: string;
createdAt: Date;
categoryLabel: string;
+ category: string;
licenceLabel: string;
+ licence: string;
languageLabel: string;
+ language: string;
description: string;
duration: string;
id: string;
author: string,
createdAt: string,
categoryLabel: string,
+ category: string,
licenceLabel: string,
+ licence: string,
languageLabel: string;
+ language: string;
description: string,
duration: number;
id: string,
this.author = hash.author;
this.createdAt = new Date(hash.createdAt);
this.categoryLabel = hash.categoryLabel;
+ this.category = hash.category;
this.licenceLabel = hash.licenceLabel;
+ this.licence = hash.licence;
this.languageLabel = hash.languageLabel;
+ this.language = hash.language;
this.description = hash.description;
this.duration = Video.createDurationString(hash.duration);
this.id = hash.id;
// If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos...
return (this.nsfw && (!user || user.displayNSFW === false));
}
+
+ patch(values: Object) {
+ Object.keys(values).forEach((key) => {
+ this[key] = values[key];
+ });
+ }
+
+ toJSON() {
+ return {
+ author: this.author,
+ createdAt: this.createdAt,
+ category: this.category,
+ licence: this.licence,
+ language: this.language,
+ description: this.description,
+ duration: this.duration,
+ id: this.id,
+ isLocal: this.isLocal,
+ magnetUri: this.magnetUri,
+ name: this.name,
+ podHost: this.podHost,
+ tags: this.tags,
+ thumbnailPath: this.thumbnailPath,
+ views: this.views,
+ likes: this.likes,
+ dislikes: this.dislikes,
+ nsfw: this.nsfw
+ };
+ }
}
import { Injectable } from '@angular/core';
-import { Http } from '@angular/http';
+import { Http, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
.catch((res) => this.restExtractor.handleError(res));
}
+ updateVideo(video: Video) {
+ const body = {
+ name: video.name,
+ category: video.category,
+ licence: video.licence,
+ language: video.language,
+ description: video.description,
+ tags: video.tags
+ };
+ const headers = new Headers({ 'Content-Type': 'application/json' });
+ const options = new RequestOptions({ headers: headers });
+
+ return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options)
+ .map(this.restExtractor.extractDataBool)
+ .catch(this.restExtractor.handleError);
+ }
+
getVideos(pagination: RestPagination, sort: SortField) {
const params = this.restService.buildRestGetParams(pagination, sort);
+++ /dev/null
-export * from './video-add.component';
+++ /dev/null
-<h3>Upload a video</h3>
-
-<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-
-<form novalidate [formGroup]="form">
- <div class="form-group">
- <label for="name">Name</label>
- <input
- type="text" class="form-control" id="name"
- formControlName="name"
- >
- <div *ngIf="formErrors.name" class="alert alert-danger">
- {{ formErrors.name }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="nsfw">NSFW</label>
- <input
- type="checkbox" id="nsfw"
- formControlName="nsfw"
- >
- </div>
-
- <div class="form-group">
- <label for="category">Category</label>
- <select class="form-control" id="category" formControlName="category">
- <option></option>
- <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
- </select>
-
- <div *ngIf="formErrors.category" class="alert alert-danger">
- {{ formErrors.category }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="licence">Licence</label>
- <select class="form-control" id="licence" formControlName="licence">
- <option></option>
- <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
- </select>
-
- <div *ngIf="formErrors.licence" class="alert alert-danger">
- {{ formErrors.licence }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="language">Language</label>
- <select class="form-control" id="language" formControlName="language">
- <option></option>
- <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
- </select>
-
- <div *ngIf="formErrors.language" class="alert alert-danger">
- {{ formErrors.language }}
- </div>
- </div>
-
- <div class="form-group">
- <label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
- <input
- type="text" class="form-control" id="currentTag"
- formControlName="currentTag" (keyup)="onTagKeyPress($event)"
- >
- <div *ngIf="formErrors.currentTag" class="alert alert-danger">
- {{ formErrors.currentTag }}
- </div>
- </div>
-
- <div class="tags">
- <div class="label label-primary tag" *ngFor="let tag of tags">
- {{ tag }}
- <span class="remove" (click)="removeTag(tag)">x</span>
- </div>
- </div>
-
- <div *ngIf="tagsError" class="alert alert-danger">
- {{ tagsError }}
- </div>
-
- <div class="form-group">
- <label for="videofile">File</label>
- <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" >
- <span>Select the video...</span>
- <input
- type="file" name="videofile" id="videofile"
- ng2FileSelect [uploader]="uploader" [disabled]="filename !== null"
- (change)="fileChanged()"
- >
- </div>
- </div>
-
- <div class="file-to-upload">
- <div class="file" *ngIf="uploader.queue.length > 0">
- <span class="filename">{{ filename }}</span>
- <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span>
- </div>
- </div>
-
- <div *ngIf="fileError" class="alert alert-danger">
- {{ fileError }}
- </div>
-
- <div class="form-group">
- <label for="description">Description</label>
- <textarea
- id="description" class="form-control" placeholder="Description..."
- formControlName="description"
- >
- </textarea>
- <div *ngIf="formErrors.description" class="alert alert-danger">
- {{ formErrors.description }}
- </div>
- </div>
-
- <div class="progress">
- <progressbar [value]="uploader.progress" max="100"></progressbar>
- </div>
-
- <div class="form-group">
- <input
- type="button" value="Upload" class="btn btn-default form-control"
- (click)="upload()"
- >
- </div>
-</form>
+++ /dev/null
-.btn-file {
- position: relative;
- overflow: hidden;
- display: block;
-}
-
-.btn-file input[type=file] {
- position: absolute;
- top: 0;
- right: 0;
- min-width: 100%;
- min-height: 100%;
- font-size: 100px;
- text-align: right;
- filter: alpha(opacity=0);
- opacity: 0;
- outline: none;
- background: white;
- cursor: inherit;
- display: block;
-}
-
-.name_file {
- display: inline-block;
- margin-left: 10px;
-}
-
-.form-group {
- margin-bottom: 10px;
-}
-
-div.tags {
- height: 40px;
- font-size: 20px;
- margin-top: 20px;
-
- .tag {
- margin-right: 10px;
-
- .remove {
- cursor: pointer;
- }
- }
-}
-
-div.file-to-upload {
- height: 40px;
-
- .glyphicon-remove {
- cursor: pointer;
- }
-}
-
-.little-information {
- font-size: 0.8em;
- font-style: italic;
-}
+++ /dev/null
-import { Component, ElementRef, OnInit } from '@angular/core';
-import { FormBuilder, FormGroup } from '@angular/forms';
-import { Router } from '@angular/router';
-
-import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
-import { NotificationsService } from 'angular2-notifications';
-
-import { AuthService } from '../../core';
-import {
- FormReactive,
- VIDEO_NAME,
- VIDEO_CATEGORY,
- VIDEO_LICENCE,
- VIDEO_LANGUAGE,
- VIDEO_DESCRIPTION,
- VIDEO_TAGS
-} from '../../shared';
-import { VideoService } from '../shared';
-
-@Component({
- selector: 'my-videos-add',
- styleUrls: [ './video-add.component.scss' ],
- templateUrl: './video-add.component.html'
-})
-
-export class VideoAddComponent extends FormReactive implements OnInit {
- tags: string[] = [];
- uploader: FileUploader;
- videoCategories = [];
- videoLicences = [];
- videoLanguages = [];
-
- error: string = null;
- form: FormGroup;
- formErrors = {
- name: '',
- category: '',
- licence: '',
- language: '',
- description: '',
- currentTag: ''
- };
- validationMessages = {
- name: VIDEO_NAME.MESSAGES,
- category: VIDEO_CATEGORY.MESSAGES,
- licence: VIDEO_LICENCE.MESSAGES,
- language: VIDEO_LANGUAGE.MESSAGES,
- description: VIDEO_DESCRIPTION.MESSAGES,
- currentTag: VIDEO_TAGS.MESSAGES
- };
-
- // Special error messages
- tagsError = '';
- fileError = '';
-
- constructor(
- private authService: AuthService,
- private elementRef: ElementRef,
- private formBuilder: FormBuilder,
- private router: Router,
- private notificationsService: NotificationsService,
- private videoService: VideoService
- ) {
- super();
- }
-
- get filename() {
- if (this.uploader.queue.length === 0) {
- return null;
- }
-
- return this.uploader.queue[0].file.name;
- }
-
- buildForm() {
- this.form = this.formBuilder.group({
- name: [ '', VIDEO_NAME.VALIDATORS ],
- nsfw: [ false ],
- category: [ '', VIDEO_CATEGORY.VALIDATORS ],
- licence: [ '', VIDEO_LICENCE.VALIDATORS ],
- language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
- description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
- currentTag: [ '', VIDEO_TAGS.VALIDATORS ]
- });
-
- this.form.valueChanges.subscribe(data => this.onValueChanged(data));
- }
-
- ngOnInit() {
- this.videoCategories = this.videoService.videoCategories;
- this.videoLicences = this.videoService.videoLicences;
- this.videoLanguages = this.videoService.videoLanguages;
-
- this.uploader = new FileUploader({
- authToken: this.authService.getRequestHeaderValue(),
- queueLimit: 1,
- url: '/api/v1/videos',
- removeAfterUpload: true
- });
-
- this.uploader.onBuildItemForm = (item, form) => {
- const name = this.form.value['name'];
- const nsfw = this.form.value['nsfw'];
- const category = this.form.value['category'];
- const licence = this.form.value['licence'];
- const language = this.form.value['language'];
- const description = this.form.value['description'];
-
- form.append('name', name);
- form.append('category', category);
- form.append('nsfw', nsfw);
- form.append('licence', licence);
-
- // Language is optional
- if (language) {
- form.append('language', language);
- }
-
- form.append('description', description);
-
- for (let i = 0; i < this.tags.length; i++) {
- form.append(`tags[${i}]`, this.tags[i]);
- }
- };
-
- this.buildForm();
- }
-
- checkForm() {
- this.forceCheck();
-
- if (this.filename === null) {
- this.fileError = 'You did not add a file.';
- }
-
- return this.form.valid === true && this.tagsError === '' && this.fileError === '';
- }
-
- fileChanged() {
- this.fileError = '';
- }
-
- onTagKeyPress(event: KeyboardEvent) {
- // Enter press
- if (event.keyCode === 13) {
- this.addTagIfPossible();
- }
- }
-
- removeFile() {
- this.uploader.clearQueue();
- }
-
- removeTag(tag: string) {
- this.tags.splice(this.tags.indexOf(tag), 1);
- this.form.get('currentTag').enable();
- }
-
- upload() {
- // Maybe the user forgot to press "enter" when he filled the field
- this.addTagIfPossible();
-
- if (this.checkForm() === false) {
- return;
- }
-
- const item = this.uploader.queue[0];
- // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242
- item.alias = 'videofile';
-
- // FIXME: remove
- // Run detection change for progress bar
- const interval = setInterval(() => { ; }, 250);
-
- item.onSuccess = () => {
- clearInterval(interval);
-
- console.log('Video uploaded.');
- this.notificationsService.success('Success', 'Video uploaded.');
-
-
- // Print all the videos once it's finished
- this.router.navigate(['/videos/list']);
- };
-
- item.onError = (response: string, status: number) => {
- clearInterval(interval);
-
- // We need to handle manually these cases beceause we use the FileUpload component
- if (status === 400) {
- this.error = response;
- } else if (status === 401) {
- this.error = 'Access token was expired, refreshing token...';
- this.authService.refreshAccessToken().subscribe(
- () => {
- // Update the uploader request header
- this.uploader.authToken = this.authService.getRequestHeaderValue();
- this.error += ' access token refreshed. Please retry your request.';
- }
- );
- } else {
- this.error = 'Unknow error';
- console.error(this.error);
- }
- };
-
- this.uploader.uploadAll();
- }
-
- private addTagIfPossible() {
- const currentTag = this.form.value['currentTag'];
- if (currentTag === undefined) return;
-
- // Check if the tag is valid and does not already exist
- if (
- currentTag.length >= 2 &&
- this.form.controls['currentTag'].valid &&
- this.tags.indexOf(currentTag) === -1
- ) {
- this.tags.push(currentTag);
- this.form.patchValue({ currentTag: '' });
-
- if (this.tags.length >= 3) {
- this.form.get('currentTag').disable();
- }
-
- this.tagsError = '';
- }
- }
-}
--- /dev/null
+export * from './video-add.component';
+export * from './video-update.component';
--- /dev/null
+<h3>Upload a video</h3>
+
+<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+
+<form novalidate [formGroup]="form">
+ <div class="form-group">
+ <label for="name">Name</label>
+ <input
+ type="text" class="form-control" id="name"
+ formControlName="name"
+ >
+ <div *ngIf="formErrors.name" class="alert alert-danger">
+ {{ formErrors.name }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="nsfw">NSFW</label>
+ <input
+ type="checkbox" id="nsfw"
+ formControlName="nsfw"
+ >
+ </div>
+
+ <div class="form-group">
+ <label for="category">Category</label>
+ <select class="form-control" id="category" formControlName="category">
+ <option></option>
+ <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.category" class="alert alert-danger">
+ {{ formErrors.category }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="licence">Licence</label>
+ <select class="form-control" id="licence" formControlName="licence">
+ <option></option>
+ <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.licence" class="alert alert-danger">
+ {{ formErrors.licence }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="language">Language</label>
+ <select class="form-control" id="language" formControlName="language">
+ <option></option>
+ <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.language" class="alert alert-danger">
+ {{ formErrors.language }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
+ <input
+ type="text" class="form-control" id="currentTag"
+ formControlName="currentTag" (keyup)="onTagKeyPress($event)"
+ >
+ <div *ngIf="formErrors.currentTag" class="alert alert-danger">
+ {{ formErrors.currentTag }}
+ </div>
+ </div>
+
+ <div class="tags">
+ <div class="label label-primary tag" *ngFor="let tag of tags">
+ {{ tag }}
+ <span class="remove" (click)="removeTag(tag)">x</span>
+ </div>
+ </div>
+
+ <div *ngIf="tagsError" class="alert alert-danger">
+ {{ tagsError }}
+ </div>
+
+ <div class="form-group">
+ <label for="videofile">File</label>
+ <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" >
+ <span>Select the video...</span>
+ <input
+ type="file" name="videofile" id="videofile"
+ ng2FileSelect [uploader]="uploader" [disabled]="filename !== null"
+ (change)="fileChanged()"
+ >
+ </div>
+ </div>
+
+ <div class="file-to-upload">
+ <div class="file" *ngIf="uploader.queue.length > 0">
+ <span class="filename">{{ filename }}</span>
+ <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span>
+ </div>
+ </div>
+
+ <div *ngIf="fileError" class="alert alert-danger">
+ {{ fileError }}
+ </div>
+
+ <div class="form-group">
+ <label for="description">Description</label>
+ <textarea
+ id="description" class="form-control" placeholder="Description..."
+ formControlName="description"
+ >
+ </textarea>
+ <div *ngIf="formErrors.description" class="alert alert-danger">
+ {{ formErrors.description }}
+ </div>
+ </div>
+
+ <div class="progress">
+ <progressbar [value]="uploader.progress" max="100"></progressbar>
+ </div>
+
+ <div class="form-group">
+ <input
+ type="button" value="Upload" class="btn btn-default form-control"
+ (click)="upload()"
+ >
+ </div>
+</form>
--- /dev/null
+import { Component, ElementRef, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { Router } from '@angular/router';
+
+import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
+import { NotificationsService } from 'angular2-notifications';
+
+import { AuthService } from '../../core';
+import {
+ FormReactive,
+ VIDEO_NAME,
+ VIDEO_CATEGORY,
+ VIDEO_LICENCE,
+ VIDEO_LANGUAGE,
+ VIDEO_DESCRIPTION,
+ VIDEO_TAGS
+} from '../../shared';
+import { VideoService } from '../shared';
+
+@Component({
+ selector: 'my-videos-add',
+ styleUrls: [ './video-edit.component.scss' ],
+ templateUrl: './video-add.component.html'
+})
+
+export class VideoAddComponent extends FormReactive implements OnInit {
+ tags: string[] = [];
+ uploader: FileUploader;
+ videoCategories = [];
+ videoLicences = [];
+ videoLanguages = [];
+
+ error: string = null;
+ form: FormGroup;
+ formErrors = {
+ name: '',
+ category: '',
+ licence: '',
+ language: '',
+ description: '',
+ currentTag: ''
+ };
+ validationMessages = {
+ name: VIDEO_NAME.MESSAGES,
+ category: VIDEO_CATEGORY.MESSAGES,
+ licence: VIDEO_LICENCE.MESSAGES,
+ language: VIDEO_LANGUAGE.MESSAGES,
+ description: VIDEO_DESCRIPTION.MESSAGES,
+ currentTag: VIDEO_TAGS.MESSAGES
+ };
+
+ // Special error messages
+ tagsError = '';
+ fileError = '';
+
+ constructor(
+ private authService: AuthService,
+ private elementRef: ElementRef,
+ private formBuilder: FormBuilder,
+ private router: Router,
+ private notificationsService: NotificationsService,
+ private videoService: VideoService
+ ) {
+ super();
+ }
+
+ get filename() {
+ if (this.uploader.queue.length === 0) {
+ return null;
+ }
+
+ return this.uploader.queue[0].file.name;
+ }
+
+ buildForm() {
+ this.form = this.formBuilder.group({
+ name: [ '', VIDEO_NAME.VALIDATORS ],
+ nsfw: [ false ],
+ category: [ '', VIDEO_CATEGORY.VALIDATORS ],
+ licence: [ '', VIDEO_LICENCE.VALIDATORS ],
+ language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
+ description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
+ currentTag: [ '', VIDEO_TAGS.VALIDATORS ]
+ });
+
+ this.form.valueChanges.subscribe(data => this.onValueChanged(data));
+ }
+
+ ngOnInit() {
+ this.videoCategories = this.videoService.videoCategories;
+ this.videoLicences = this.videoService.videoLicences;
+ this.videoLanguages = this.videoService.videoLanguages;
+
+ this.uploader = new FileUploader({
+ authToken: this.authService.getRequestHeaderValue(),
+ queueLimit: 1,
+ url: '/api/v1/videos',
+ removeAfterUpload: true
+ });
+
+ this.uploader.onBuildItemForm = (item, form) => {
+ const name = this.form.value['name'];
+ const nsfw = this.form.value['nsfw'];
+ const category = this.form.value['category'];
+ const licence = this.form.value['licence'];
+ const language = this.form.value['language'];
+ const description = this.form.value['description'];
+
+ form.append('name', name);
+ form.append('category', category);
+ form.append('nsfw', nsfw);
+ form.append('licence', licence);
+
+ // Language is optional
+ if (language) {
+ form.append('language', language);
+ }
+
+ form.append('description', description);
+
+ for (let i = 0; i < this.tags.length; i++) {
+ form.append(`tags[${i}]`, this.tags[i]);
+ }
+ };
+
+ this.buildForm();
+ }
+
+ checkForm() {
+ this.forceCheck();
+
+ if (this.filename === null) {
+ this.fileError = 'You did not add a file.';
+ }
+
+ return this.form.valid === true && this.tagsError === '' && this.fileError === '';
+ }
+
+ fileChanged() {
+ this.fileError = '';
+ }
+
+ onTagKeyPress(event: KeyboardEvent) {
+ // Enter press
+ if (event.keyCode === 13) {
+ this.addTagIfPossible();
+ }
+ }
+
+ removeFile() {
+ this.uploader.clearQueue();
+ }
+
+ removeTag(tag: string) {
+ this.tags.splice(this.tags.indexOf(tag), 1);
+ this.form.get('currentTag').enable();
+ }
+
+ upload() {
+ // Maybe the user forgot to press "enter" when he filled the field
+ this.addTagIfPossible();
+
+ if (this.checkForm() === false) {
+ return;
+ }
+
+ const item = this.uploader.queue[0];
+ // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242
+ item.alias = 'videofile';
+
+ // FIXME: remove
+ // Run detection change for progress bar
+ const interval = setInterval(() => { ; }, 250);
+
+ item.onSuccess = () => {
+ clearInterval(interval);
+
+ console.log('Video uploaded.');
+ this.notificationsService.success('Success', 'Video uploaded.');
+
+
+ // Print all the videos once it's finished
+ this.router.navigate(['/videos/list']);
+ };
+
+ item.onError = (response: string, status: number) => {
+ clearInterval(interval);
+
+ // We need to handle manually these cases beceause we use the FileUpload component
+ if (status === 400) {
+ this.error = response;
+ } else if (status === 401) {
+ this.error = 'Access token was expired, refreshing token...';
+ this.authService.refreshAccessToken().subscribe(
+ () => {
+ // Update the uploader request header
+ this.uploader.authToken = this.authService.getRequestHeaderValue();
+ this.error += ' access token refreshed. Please retry your request.';
+ }
+ );
+ } else {
+ this.error = 'Unknow error';
+ console.error(this.error);
+ }
+ };
+
+ this.uploader.uploadAll();
+ }
+
+ private addTagIfPossible() {
+ const currentTag = this.form.value['currentTag'];
+ if (currentTag === undefined) return;
+
+ // Check if the tag is valid and does not already exist
+ if (
+ currentTag.length >= 2 &&
+ this.form.controls['currentTag'].valid &&
+ this.tags.indexOf(currentTag) === -1
+ ) {
+ this.tags.push(currentTag);
+ this.form.patchValue({ currentTag: '' });
+
+ if (this.tags.length >= 3) {
+ this.form.get('currentTag').disable();
+ }
+
+ this.tagsError = '';
+ }
+ }
+}
--- /dev/null
+.btn-file {
+ position: relative;
+ overflow: hidden;
+ display: block;
+}
+
+.btn-file input[type=file] {
+ position: absolute;
+ top: 0;
+ right: 0;
+ min-width: 100%;
+ min-height: 100%;
+ font-size: 100px;
+ text-align: right;
+ filter: alpha(opacity=0);
+ opacity: 0;
+ outline: none;
+ background: white;
+ cursor: inherit;
+ display: block;
+}
+
+.name_file {
+ display: inline-block;
+ margin-left: 10px;
+}
+
+.form-group {
+ margin-bottom: 10px;
+}
+
+div.tags {
+ height: 40px;
+ font-size: 20px;
+ margin-top: 20px;
+
+ .tag {
+ margin-right: 10px;
+
+ .remove {
+ cursor: pointer;
+ }
+ }
+}
+
+div.file-to-upload {
+ height: 40px;
+
+ .glyphicon-remove {
+ cursor: pointer;
+ }
+}
+
+.little-information {
+ font-size: 0.8em;
+ font-style: italic;
+}
--- /dev/null
+<h3>Update {{ video.name }}</h3>
+
+<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
+
+<form novalidate [formGroup]="form">
+ <div class="form-group">
+ <label for="name">Name</label>
+ <input
+ type="text" class="form-control" id="name"
+ formControlName="name"
+ >
+ <div *ngIf="formErrors.name" class="alert alert-danger">
+ {{ formErrors.name }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="nsfw">NSFW</label>
+ <input
+ type="checkbox" id="nsfw"
+ formControlName="nsfw"
+ >
+ </div>
+
+ <div class="form-group">
+ <label for="category">Category</label>
+ <select class="form-control" id="category" formControlName="category">
+ <option></option>
+ <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.category" class="alert alert-danger">
+ {{ formErrors.category }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="licence">Licence</label>
+ <select class="form-control" id="licence" formControlName="licence">
+ <option></option>
+ <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.licence" class="alert alert-danger">
+ {{ formErrors.licence }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="language">Language</label>
+ <select class="form-control" id="language" formControlName="language">
+ <option></option>
+ <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
+ </select>
+
+ <div *ngIf="formErrors.language" class="alert alert-danger">
+ {{ formErrors.language }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
+ <input
+ type="text" class="form-control" id="currentTag"
+ formControlName="currentTag" (keyup)="onTagKeyPress($event)"
+ >
+ <div *ngIf="formErrors.currentTag" class="alert alert-danger">
+ {{ formErrors.currentTag }}
+ </div>
+ </div>
+
+ <div class="tags">
+ <div class="label label-primary tag" *ngFor="let tag of tags">
+ {{ tag }}
+ <span class="remove" (click)="removeTag(tag)">x</span>
+ </div>
+ </div>
+
+ <div *ngIf="tagsError" class="alert alert-danger">
+ {{ tagsError }}
+ </div>
+
+ <div class="form-group">
+ <label for="description">Description</label>
+ <textarea
+ id="description" class="form-control" placeholder="Description..."
+ formControlName="description"
+ >
+ </textarea>
+ <div *ngIf="formErrors.description" class="alert alert-danger">
+ {{ formErrors.description }}
+ </div>
+ </div>
+
+ <div class="form-group">
+ <input
+ type="button" value="Update" class="btn btn-default form-control"
+ (click)="update()"
+ >
+ </div>
+</form>
--- /dev/null
+import { Component, ElementRef, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+
+import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
+import { NotificationsService } from 'angular2-notifications';
+
+import { AuthService } from '../../core';
+import {
+ FormReactive,
+ VIDEO_NAME,
+ VIDEO_CATEGORY,
+ VIDEO_LICENCE,
+ VIDEO_LANGUAGE,
+ VIDEO_DESCRIPTION,
+ VIDEO_TAGS
+} from '../../shared';
+import { Video, VideoService } from '../shared';
+
+@Component({
+ selector: 'my-videos-update',
+ styleUrls: [ './video-edit.component.scss' ],
+ templateUrl: './video-update.component.html'
+})
+
+export class VideoUpdateComponent extends FormReactive implements OnInit {
+ tags: string[] = [];
+ videoCategories = [];
+ videoLicences = [];
+ videoLanguages = [];
+ video: Video;
+
+ error: string = null;
+ form: FormGroup;
+ formErrors = {
+ name: '',
+ category: '',
+ licence: '',
+ language: '',
+ description: '',
+ currentTag: ''
+ };
+ validationMessages = {
+ name: VIDEO_NAME.MESSAGES,
+ category: VIDEO_CATEGORY.MESSAGES,
+ licence: VIDEO_LICENCE.MESSAGES,
+ language: VIDEO_LANGUAGE.MESSAGES,
+ description: VIDEO_DESCRIPTION.MESSAGES,
+ currentTag: VIDEO_TAGS.MESSAGES
+ };
+
+ // Special error messages
+ tagsError = '';
+ fileError = '';
+
+ constructor(
+ private authService: AuthService,
+ private elementRef: ElementRef,
+ private formBuilder: FormBuilder,
+ private route: ActivatedRoute,
+ private router: Router,
+ private notificationsService: NotificationsService,
+ private videoService: VideoService
+ ) {
+ super();
+ }
+
+ buildForm() {
+ this.form = this.formBuilder.group({
+ name: [ '', VIDEO_NAME.VALIDATORS ],
+ nsfw: [ false ],
+ category: [ '', VIDEO_CATEGORY.VALIDATORS ],
+ licence: [ '', VIDEO_LICENCE.VALIDATORS ],
+ language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
+ description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
+ currentTag: [ '', VIDEO_TAGS.VALIDATORS ]
+ });
+
+ this.form.valueChanges.subscribe(data => this.onValueChanged(data));
+ }
+
+ ngOnInit() {
+ this.buildForm();
+
+ this.videoCategories = this.videoService.videoCategories;
+ this.videoLicences = this.videoService.videoLicences;
+ this.videoLanguages = this.videoService.videoLanguages;
+
+ const id = this.route.snapshot.params['id'];
+ this.videoService.getVideo(id)
+ .subscribe(
+ video => {
+ this.video = video;
+
+ this.hydrateFormFromVideo();
+ },
+
+ err => this.error = 'Cannot fetch video.'
+ );
+ }
+
+ checkForm() {
+ this.forceCheck();
+
+ return this.form.valid === true && this.tagsError === '' && this.fileError === '';
+ }
+
+
+ onTagKeyPress(event: KeyboardEvent) {
+ // Enter press
+ if (event.keyCode === 13) {
+ this.addTagIfPossible();
+ }
+ }
+
+ removeTag(tag: string) {
+ this.tags.splice(this.tags.indexOf(tag), 1);
+ this.form.get('currentTag').enable();
+ }
+
+ update() {
+ // Maybe the user forgot to press "enter" when he filled the field
+ this.addTagIfPossible();
+
+ if (this.checkForm() === false) {
+ return;
+ }
+
+ this.video.patch(this.form.value);
+
+ this.videoService.updateVideo(this.video)
+ .subscribe(
+ () => {
+ this.notificationsService.success('Success', 'Video updated.');
+ this.router.navigate([ '/videos/watch', this.video.id ]);
+ },
+
+ err => {
+ this.error = 'Cannot update the video.';
+ console.error(err);
+ }
+ );
+
+ }
+
+ private addTagIfPossible() {
+ const currentTag = this.form.value['currentTag'];
+ if (currentTag === undefined) return;
+
+ // Check if the tag is valid and does not already exist
+ if (
+ currentTag.length >= 2 &&
+ this.form.controls['currentTag'].valid &&
+ this.tags.indexOf(currentTag) === -1
+ ) {
+ this.tags.push(currentTag);
+ this.form.patchValue({ currentTag: '' });
+
+ if (this.tags.length >= 3) {
+ this.form.get('currentTag').disable();
+ }
+
+ this.tagsError = '';
+ }
+ }
+
+ private hydrateFormFromVideo() {
+ this.form.patchValue(this.video.toJSON());
+ }
+}
</button>
<ul dropdownMenu id="more-menu" role="menu" aria-labelledby="single-button">
+ <li *ngIf="canUserUpdateVideo()" role="menuitem">
+ <a class="dropdown-item" title="Update this video" href="#" [routerLink]="[ '/videos/edit', video.id ]">
+ <span class="glyphicon glyphicon-pencil"></span> Update
+ </a>
+ </li>
+
<li role="menuitem">
<a class="dropdown-item" title="Get magnet URI" href="#" (click)="showMagnetUriModal($event)">
<span class="glyphicon glyphicon-magnet"></span> Magnet
return this.authService.isLoggedIn();
}
+ canUserUpdateVideo() {
+ return this.authService.getUser() !== null &&
+ this.authService.getUser().username === this.video.author;
+ }
+
private checkUserRating() {
// Unlogged users do not have ratings
if (this.isUserLoggedIn() === false) return;
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
-import { VideoAddComponent } from './video-add';
+import { VideoAddComponent, VideoUpdateComponent } from './video-edit';
import { VideoListComponent } from './video-list';
import { VideosComponent } from './videos.component';
import { VideoWatchComponent } from './video-watch';
}
}
},
+ {
+ path: 'edit/:id',
+ component: VideoUpdateComponent,
+ data: {
+ meta: {
+ title: 'Edit a video'
+ }
+ }
+ },
{
path: ':id',
redirectTo: 'watch/:id'
import { VideosRoutingModule } from './videos-routing.module';
import { VideosComponent } from './videos.component';
-import { VideoAddComponent } from './video-add';
+import { VideoAddComponent, VideoUpdateComponent } from './video-edit';
import { VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list';
import {
VideoWatchComponent,
VideosComponent,
VideoAddComponent,
+ VideoUpdateComponent,
VideoListComponent,
VideoMiniatureComponent,