From e822fdaeee90cb7c70d5678f19249198cd7aae8c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 7 Jun 2016 22:34:02 +0200 Subject: Use ng2-file-upload instead of jquery and add tags support to the video upload form --- client/src/app/shared/search/search-field.type.ts | 2 +- client/src/app/shared/search/search.component.ts | 3 +- client/src/app/shared/users/auth.service.ts | 6 +- .../app/videos/video-add/video-add.component.html | 64 ++++++-- .../app/videos/video-add/video-add.component.scss | 27 +++- .../app/videos/video-add/video-add.component.ts | 162 ++++++++++++++------- 6 files changed, 191 insertions(+), 73 deletions(-) (limited to 'client/src/app') diff --git a/client/src/app/shared/search/search-field.type.ts b/client/src/app/shared/search/search-field.type.ts index 846236290..5228ee68a 100644 --- a/client/src/app/shared/search/search-field.type.ts +++ b/client/src/app/shared/search/search-field.type.ts @@ -1 +1 @@ -export type SearchField = "name" | "author" | "podUrl" | "magnetUri"; +export type SearchField = "name" | "author" | "podUrl" | "magnetUri" | "tags"; diff --git a/client/src/app/shared/search/search.component.ts b/client/src/app/shared/search/search.component.ts index 31f8b1535..c14c2d99c 100644 --- a/client/src/app/shared/search/search.component.ts +++ b/client/src/app/shared/search/search.component.ts @@ -18,7 +18,8 @@ export class SearchComponent { name: 'Name', author: 'Author', podUrl: 'Pod Url', - magnetUri: 'Magnet Uri' + magnetUri: 'Magnet Uri', + tags: 'Tags' }; searchCriterias: Search = { field: 'name', diff --git a/client/src/app/shared/users/auth.service.ts b/client/src/app/shared/users/auth.service.ts index 720037563..1c822c1e1 100644 --- a/client/src/app/shared/users/auth.service.ts +++ b/client/src/app/shared/users/auth.service.ts @@ -43,7 +43,11 @@ export class AuthService { } getRequestHeader() { - return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` }); + return new Headers({ 'Authorization': this.getRequestHeaderValue() }); + } + + getRequestHeaderValue() { + return `${this.getTokenType()} ${this.getToken()}`; } getToken() { diff --git a/client/src/app/videos/video-add/video-add.component.html b/client/src/app/videos/video-add/video-add.component.html index cbe274e8a..6b2eb9377 100644 --- a/client/src/app/videos/video-add/video-add.component.html +++ b/client/src/app/videos/video-add/video-add.component.html @@ -2,42 +2,74 @@
{{ error }}
-
+
- + -
- Name is required +
+ A name is required and should be between 3 and 50 characters long
-
+ + +
+ A tag should be between 2 and 10 characters long +
+
+ +
+
+ {{ tag }} + x +
+
+ +
+ +
Select the video... - +
+
- {{ fileToUpload.name }} +
+
+ {{ filename }} + +
-
- A description is required +
+ A description is required and should be between 3 and 250 characters long
-
- {{ progressBar.value | bytes }} / {{ progressBar.max | bytes }} +
+
- +
+ +
diff --git a/client/src/app/videos/video-add/video-add.component.scss b/client/src/app/videos/video-add/video-add.component.scss index 01195f017..d66df2fd4 100644 --- a/client/src/app/videos/video-add/video-add.component.scss +++ b/client/src/app/videos/video-add/video-add.component.scss @@ -1,6 +1,7 @@ .btn-file { position: relative; overflow: hidden; + display: block; } .btn-file input[type=file] { @@ -28,6 +29,28 @@ margin-bottom: 10px; } -#progress { - 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; + } +} + +div.progress { + // height: 40px; } diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-add/video-add.component.ts index 144879a54..2b45ea125 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-add/video-add.component.ts @@ -1,29 +1,31 @@ -/// -/// - +import { Control, ControlGroup, Validators } from '@angular/common'; import { Component, ElementRef, OnInit } from '@angular/core'; import { Router } from '@angular/router-deprecated'; import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; import { PROGRESSBAR_DIRECTIVES } from 'ng2-bootstrap/components/progressbar'; +import { FileSelectDirective, FileUploader } from 'ng2-file-upload/ng2-file-upload'; -import { AuthService, User } from '../../shared'; +import { AuthService } from '../../shared'; @Component({ selector: 'my-videos-add', styles: [ require('./video-add.component.scss') ], template: require('./video-add.component.html'), - directives: [ PROGRESSBAR_DIRECTIVES ], + directives: [ FileSelectDirective, PROGRESSBAR_DIRECTIVES ], pipes: [ BytesPipe ] }) export class VideoAddComponent implements OnInit { + currentTag: string; // Tag the user is writing in the input error: string = null; - fileToUpload: any; - progressBar: { value: number; max: number; } = { value: 0, max: 0 }; - user: User; - - private form: any; + videoForm: ControlGroup; + uploader: FileUploader; + video = { + name: '', + tags: [], + description: '' + }; constructor( private authService: AuthService, @@ -31,52 +33,108 @@ export class VideoAddComponent implements OnInit { private router: Router ) {} + get filename() { + if (this.uploader.queue.length === 0) { + return null; + } + + return this.uploader.queue[0].file.name; + } + + get isTagsInputDisabled () { + return this.video.tags.length >= 3; + } + + getInvalidFieldsTitle() { + let title = ''; + const nameControl = this.videoForm.controls['name']; + const descriptionControl = this.videoForm.controls['description']; + + if (!nameControl.valid) { + title += 'A name is required\n'; + } + + if (this.video.tags.length === 0) { + title += 'At least one tag is required\n'; + } + + if (this.filename === null) { + title += 'A file is required\n'; + } + + if (!descriptionControl.valid) { + title += 'A description is required\n'; + } + + return title; + } + ngOnInit() { - this.user = User.load(); - jQuery(this.elementRef.nativeElement).find('#videofile').fileupload({ + this.videoForm = new ControlGroup({ + name: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(50) ])), + description: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(250) ])), + tags: new Control('', Validators.pattern('^[a-zA-Z0-9]{2,10}$')) + }); + + + this.uploader = new FileUploader({ + authToken: this.authService.getRequestHeaderValue(), + queueLimit: 1, url: '/api/v1/videos', - dataType: 'json', - singleFileUploads: true, - multipart: true, - autoUpload: false, - - add: (e, data) => { - this.form = data; - this.fileToUpload = data['files'][0]; - }, - - progressall: (e, data) => { - this.progressBar.value = data.loaded; - // The server is a little bit slow to answer (has to seed the video) - // So we add more time to the progress bar (+10%) - this.progressBar.max = data.total + (0.1 * data.total); - }, - - done: (e, data) => { - this.progressBar.value = this.progressBar.max; - console.log('Video uploaded.'); - - // Print all the videos once it's finished - this.router.navigate(['VideosList']); - }, - - fail: (e, data) => { - const xhr = data.jqXHR; - if (xhr.status === 400) { - this.error = xhr.responseText; - } else { - this.error = 'Unknow error'; - } - - console.error(data); - } + removeAfterUpload: true }); + + this.uploader.onBuildItemForm = (item, form) => { + form.append('name', this.video.name); + form.append('description', this.video.description); + + for (let i = 0; i < this.video.tags.length; i++) { + form.append(`tags[${i}]`, this.video.tags[i]); + } + }; + } + + onTagKeyPress(event: KeyboardEvent) { + // Enter press + if (event.keyCode === 13) { + // Check if the tag is valid and does not already exist + if ( + this.currentTag !== '' && + this.videoForm.controls['tags'].valid && + this.video.tags.indexOf(this.currentTag) === -1 + ) { + this.video.tags.push(this.currentTag); + this.currentTag = ''; + } + } + } + + removeFile() { + this.uploader.clearQueue(); + } + + removeTag(tag: string) { + this.video.tags.splice(this.video.tags.indexOf(tag), 1); } - uploadFile() { - this.error = null; - this.form.formData = jQuery(this.elementRef.nativeElement).find('form').serializeArray(); - this.form.headers = this.authService.getRequestHeader().toJSON(); - this.form.submit(); + upload() { + const item = this.uploader.queue[0]; + // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 + item.alias = 'videofile'; + + item.onSuccess = () => { + console.log('Video uploaded.'); + + // Print all the videos once it's finished + this.router.navigate(['VideosList']); + }; + + item.onError = (response: string, status: number) => { + this.error = (status === 400) ? response : 'Unknow error'; + console.error(this.error); + }; + + + this.uploader.uploadAll(); } } -- cgit v1.2.3