aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos/+video-edit
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/videos/+video-edit')
-rw-r--r--client/src/app/videos/+video-edit/index.ts2
-rw-r--r--client/src/app/videos/+video-edit/video-add-routing.module.ts20
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.html121
-rw-r--r--client/src/app/videos/+video-edit/video-add.component.ts165
-rw-r--r--client/src/app/videos/+video-edit/video-add.module.ts30
-rw-r--r--client/src/app/videos/+video-edit/video-edit.component.scss56
-rw-r--r--client/src/app/videos/+video-edit/video-update-routing.module.ts20
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.html92
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.ts134
-rw-r--r--client/src/app/videos/+video-edit/video-update.module.ts30
10 files changed, 670 insertions, 0 deletions
diff --git a/client/src/app/videos/+video-edit/index.ts b/client/src/app/videos/+video-edit/index.ts
new file mode 100644
index 000000000..63e0414dd
--- /dev/null
+++ b/client/src/app/videos/+video-edit/index.ts
@@ -0,0 +1,2 @@
1export * from './video-add.module'
2export * from './video-update.module'
diff --git a/client/src/app/videos/+video-edit/video-add-routing.module.ts b/client/src/app/videos/+video-edit/video-add-routing.module.ts
new file mode 100644
index 000000000..9e8fa4acc
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-add-routing.module.ts
@@ -0,0 +1,20 @@
1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router'
3
4import { MetaGuard } from '@ngx-meta/core'
5
6import { VideoAddComponent } from './video-add.component'
7
8const videoAddRoutes: Routes = [
9 {
10 path: '',
11 component: VideoAddComponent,
12 canActivateChild: [ MetaGuard ]
13 }
14]
15
16@NgModule({
17 imports: [ RouterModule.forChild(videoAddRoutes) ],
18 exports: [ RouterModule ]
19})
20export class VideoAddRoutingModule {}
diff --git a/client/src/app/videos/+video-edit/video-add.component.html b/client/src/app/videos/+video-edit/video-add.component.html
new file mode 100644
index 000000000..698152ff9
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-add.component.html
@@ -0,0 +1,121 @@
1<div class="row">
2 <div class="content-padding">
3
4 <h3>Upload a video</h3>
5
6 <div *ngIf="error !== undefined" class="alert alert-danger">{{ error }}</div>
7
8 <form novalidate [formGroup]="form">
9 <div class="form-group">
10 <label for="name">Name</label>
11 <input
12 type="text" class="form-control" id="name"
13 formControlName="name"
14 >
15 <div *ngIf="formErrors.name" class="alert alert-danger">
16 {{ formErrors.name }}
17 </div>
18 </div>
19
20 <div class="form-group">
21 <label for="nsfw">NSFW</label>
22 <input
23 type="checkbox" id="nsfw"
24 formControlName="nsfw"
25 >
26 </div>
27
28 <div class="form-group">
29 <label for="category">Category</label>
30 <select class="form-control" id="category" formControlName="category">
31 <option></option>
32 <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
33 </select>
34
35 <div *ngIf="formErrors.category" class="alert alert-danger">
36 {{ formErrors.category }}
37 </div>
38 </div>
39
40 <div class="form-group">
41 <label for="licence">Licence</label>
42 <select class="form-control" id="licence" formControlName="licence">
43 <option></option>
44 <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
45 </select>
46
47 <div *ngIf="formErrors.licence" class="alert alert-danger">
48 {{ formErrors.licence }}
49 </div>
50 </div>
51
52 <div class="form-group">
53 <label for="language">Language</label>
54 <select class="form-control" id="language" formControlName="language">
55 <option></option>
56 <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
57 </select>
58
59 <div *ngIf="formErrors.language" class="alert alert-danger">
60 {{ formErrors.language }}
61 </div>
62 </div>
63
64 <div class="form-group">
65 <label class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
66 <tag-input
67 [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
68 formControlName="tags" maxItems="3" modelAsStrings="true"
69 ></tag-input>
70 </div>
71
72 <div class="form-group">
73 <label for="videofile">File</label>
74 <div class="btn btn-default btn-file">
75 <span>Select the video...</span>
76 <input #videofileInput type="file" name="videofile" id="videofile" (change)="fileChange($event)" />
77 <input type="hidden" name="videofileHidden" formControlName="videofile"/>
78 </div>
79 </div>
80
81 <div class="file-to-upload">
82 <div class="file" *ngIf="filename">
83 <span class="filename">{{ filename }}</span>
84 <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span>
85 </div>
86 </div>
87
88 <div *ngIf="formErrors.videofile" class="alert alert-danger">
89 {{ formErrors.videofile }}
90 </div>
91
92 <div class="form-group">
93 <label for="description">Description</label>
94 <textarea
95 id="description" class="form-control" placeholder="Description..."
96 formControlName="description"
97 >
98 </textarea>
99 <div *ngIf="formErrors.description" class="alert alert-danger">
100 {{ formErrors.description }}
101 </div>
102 </div>
103
104 <div class="progress">
105 <progressbar [value]="progressPercent" max="100">
106 <ng-template [ngIf]="progressPercent === 100">
107 <span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>
108 Server is processing the video
109 </ng-template>
110 </progressbar>
111 </div>
112
113 <div class="form-group">
114 <input
115 type="button" value="Upload" class="btn btn-default form-control"
116 (click)="upload()"
117 >
118 </div>
119 </form>
120 </div>
121</div>
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts
new file mode 100644
index 000000000..21311b184
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-add.component.ts
@@ -0,0 +1,165 @@
1import { Component, OnInit, ViewChild } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms'
3import { Router } from '@angular/router'
4
5import { NotificationsService } from 'angular2-notifications'
6
7import {
8 FormReactive,
9 VIDEO_NAME,
10 VIDEO_CATEGORY,
11 VIDEO_LICENCE,
12 VIDEO_LANGUAGE,
13 VIDEO_DESCRIPTION,
14 VIDEO_TAGS
15} from '../../shared'
16import { VideoService } from '../shared'
17import { VideoCreate } from '../../../../../shared'
18import { HttpEventType, HttpResponse } from '@angular/common/http'
19import { VIDEO_FILE } from '../../shared/forms/form-validators/video'
20
21@Component({
22 selector: 'my-videos-add',
23 styleUrls: [ './video-edit.component.scss' ],
24 templateUrl: './video-add.component.html'
25})
26
27export class VideoAddComponent extends FormReactive implements OnInit {
28 @ViewChild('videofileInput') videofileInput
29
30 progressPercent = 0
31 tags: string[] = []
32 videoCategories = []
33 videoLicences = []
34 videoLanguages = []
35
36 tagValidators = VIDEO_TAGS.VALIDATORS
37 tagValidatorsMessages = VIDEO_TAGS.MESSAGES
38
39 error: string
40 form: FormGroup
41 formErrors = {
42 name: '',
43 category: '',
44 licence: '',
45 language: '',
46 description: '',
47 videofile: ''
48 }
49 validationMessages = {
50 name: VIDEO_NAME.MESSAGES,
51 category: VIDEO_CATEGORY.MESSAGES,
52 licence: VIDEO_LICENCE.MESSAGES,
53 language: VIDEO_LANGUAGE.MESSAGES,
54 description: VIDEO_DESCRIPTION.MESSAGES,
55 videofile: VIDEO_FILE.MESSAGES
56 }
57
58 constructor (
59 private formBuilder: FormBuilder,
60 private router: Router,
61 private notificationsService: NotificationsService,
62 private videoService: VideoService
63 ) {
64 super()
65 }
66
67 get filename () {
68 return this.form.value['videofile']
69 }
70
71 buildForm () {
72 this.form = this.formBuilder.group({
73 name: [ '', VIDEO_NAME.VALIDATORS ],
74 nsfw: [ false ],
75 category: [ '', VIDEO_CATEGORY.VALIDATORS ],
76 licence: [ '', VIDEO_LICENCE.VALIDATORS ],
77 language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
78 description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
79 videofile: [ '', VIDEO_FILE.VALIDATORS ],
80 tags: [ '' ]
81 })
82
83 this.form.valueChanges.subscribe(data => this.onValueChanged(data))
84 }
85
86 ngOnInit () {
87 this.videoCategories = this.videoService.videoCategories
88 this.videoLicences = this.videoService.videoLicences
89 this.videoLanguages = this.videoService.videoLanguages
90
91 this.buildForm()
92 }
93
94 // The goal is to keep reactive form validation (required field)
95 // https://stackoverflow.com/a/44238894
96 fileChange ($event) {
97 this.form.controls['videofile'].setValue($event.target.files[0].name)
98 }
99
100 removeFile () {
101 this.videofileInput.nativeElement.value = ''
102 this.form.controls['videofile'].setValue('')
103 }
104
105 checkForm () {
106 this.forceCheck()
107
108 return this.form.valid
109 }
110
111 upload () {
112 if (this.checkForm() === false) {
113 return
114 }
115
116 const formValue: VideoCreate = this.form.value
117
118 const name = formValue.name
119 const nsfw = formValue.nsfw
120 const category = formValue.category
121 const licence = formValue.licence
122 const language = formValue.language
123 const description = formValue.description
124 const tags = formValue.tags
125 const videofile = this.videofileInput.nativeElement.files[0]
126
127 const formData = new FormData()
128 formData.append('name', name)
129 formData.append('category', '' + category)
130 formData.append('nsfw', '' + nsfw)
131 formData.append('licence', '' + licence)
132 formData.append('videofile', videofile)
133
134 // Language is optional
135 if (language) {
136 formData.append('language', '' + language)
137 }
138
139 formData.append('description', description)
140
141 for (let i = 0; i < tags.length; i++) {
142 formData.append(`tags[${i}]`, tags[i])
143 }
144
145 this.videoService.uploadVideo(formData).subscribe(
146 event => {
147 if (event.type === HttpEventType.UploadProgress) {
148 this.progressPercent = Math.round(100 * event.loaded / event.total)
149 } else if (event instanceof HttpResponse) {
150 console.log('Video uploaded.')
151 this.notificationsService.success('Success', 'Video uploaded.')
152
153 // Display all the videos once it's finished
154 this.router.navigate([ '/videos/list' ])
155 }
156 },
157
158 err => {
159 // Reset progress
160 this.progressPercent = 0
161 this.error = err.message
162 }
163 )
164 }
165}
diff --git a/client/src/app/videos/+video-edit/video-add.module.ts b/client/src/app/videos/+video-edit/video-add.module.ts
new file mode 100644
index 000000000..141d33ad2
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-add.module.ts
@@ -0,0 +1,30 @@
1import { NgModule } from '@angular/core'
2
3import { TagInputModule } from 'ngx-chips'
4
5import { VideoAddRoutingModule } from './video-add-routing.module'
6import { VideoAddComponent } from './video-add.component'
7import { VideoService } from '../shared'
8import { SharedModule } from '../../shared'
9
10@NgModule({
11 imports: [
12 TagInputModule,
13
14 VideoAddRoutingModule,
15 SharedModule
16 ],
17
18 declarations: [
19 VideoAddComponent
20 ],
21
22 exports: [
23 VideoAddComponent
24 ],
25
26 providers: [
27 VideoService
28 ]
29})
30export class VideoAddModule { }
diff --git a/client/src/app/videos/+video-edit/video-edit.component.scss b/client/src/app/videos/+video-edit/video-edit.component.scss
new file mode 100644
index 000000000..9ee0c520c
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-edit.component.scss
@@ -0,0 +1,56 @@
1.btn-file {
2 position: relative;
3 overflow: hidden;
4 display: block;
5}
6
7.btn-file input[type=file] {
8 position: absolute;
9 top: 0;
10 right: 0;
11 min-width: 100%;
12 min-height: 100%;
13 font-size: 100px;
14 text-align: right;
15 filter: alpha(opacity=0);
16 opacity: 0;
17 outline: none;
18 background: white;
19 cursor: inherit;
20 display: block;
21}
22
23.form-group {
24 margin-bottom: 10px;
25}
26
27div.tags {
28 height: 40px;
29 font-size: 20px;
30 margin-top: 20px;
31
32 .tag {
33 margin-right: 10px;
34
35 .remove {
36 cursor: pointer;
37 }
38 }
39}
40
41div.file-to-upload {
42 height: 40px;
43
44 .glyphicon-remove {
45 cursor: pointer;
46 }
47}
48
49.little-information {
50 font-size: 0.8em;
51 font-style: italic;
52}
53
54.label-tags {
55 margin-bottom: 0;
56}
diff --git a/client/src/app/videos/+video-edit/video-update-routing.module.ts b/client/src/app/videos/+video-edit/video-update-routing.module.ts
new file mode 100644
index 000000000..1d06a7ac3
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-update-routing.module.ts
@@ -0,0 +1,20 @@
1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router'
3
4import { MetaGuard } from '@ngx-meta/core'
5
6import { VideoUpdateComponent } from './video-update.component'
7
8const videoUpdateRoutes: Routes = [
9 {
10 path: '',
11 component: VideoUpdateComponent,
12 canActivateChild: [ MetaGuard ]
13 }
14]
15
16@NgModule({
17 imports: [ RouterModule.forChild(videoUpdateRoutes) ],
18 exports: [ RouterModule ]
19})
20export class VideoUpdateRoutingModule {}
diff --git a/client/src/app/videos/+video-edit/video-update.component.html b/client/src/app/videos/+video-edit/video-update.component.html
new file mode 100644
index 000000000..7f4faf21b
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-update.component.html
@@ -0,0 +1,92 @@
1<div class="row">
2 <div class="content-padding">
3
4 <h3>Update {{ video?.name }}</h3>
5
6 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
7
8 <form novalidate [formGroup]="form">
9 <div class="form-group">
10 <label for="name">Name</label>
11 <input
12 type="text" class="form-control" id="name"
13 formControlName="name"
14 >
15 <div *ngIf="formErrors.name" class="alert alert-danger">
16 {{ formErrors.name }}
17 </div>
18 </div>
19
20 <div class="form-group">
21 <label for="nsfw">NSFW</label>
22 <input
23 type="checkbox" id="nsfw"
24 formControlName="nsfw"
25 >
26 </div>
27
28 <div class="form-group">
29 <label for="category">Category</label>
30 <select class="form-control" id="category" formControlName="category">
31 <option></option>
32 <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
33 </select>
34
35 <div *ngIf="formErrors.category" class="alert alert-danger">
36 {{ formErrors.category }}
37 </div>
38 </div>
39
40 <div class="form-group">
41 <label for="licence">Licence</label>
42 <select class="form-control" id="licence" formControlName="licence">
43 <option></option>
44 <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
45 </select>
46
47 <div *ngIf="formErrors.licence" class="alert alert-danger">
48 {{ formErrors.licence }}
49 </div>
50 </div>
51
52 <div class="form-group">
53 <label for="language">Language</label>
54 <select class="form-control" id="language" formControlName="language">
55 <option></option>
56 <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
57 </select>
58
59 <div *ngIf="formErrors.language" class="alert alert-danger">
60 {{ formErrors.language }}
61 </div>
62 </div>
63
64 <div class="form-group">
65 <label for="tags" class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
66 <tag-input
67 [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
68 formControlName="tags" maxItems="3" modelAsStrings="true"
69 ></tag-input>
70 </div>
71
72 <div class="form-group">
73 <label for="description">Description</label>
74 <textarea
75 id="description" class="form-control" placeholder="Description..."
76 formControlName="description"
77 >
78 </textarea>
79 <div *ngIf="formErrors.description" class="alert alert-danger">
80 {{ formErrors.description }}
81 </div>
82 </div>
83
84 <div class="form-group">
85 <input
86 type="button" value="Update" class="btn btn-default form-control"
87 (click)="update()"
88 >
89 </div>
90 </form>
91 </div>
92</div>
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts
new file mode 100644
index 000000000..141ed3522
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -0,0 +1,134 @@
1import { Component, ElementRef, OnInit } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router'
4
5import { NotificationsService } from 'angular2-notifications'
6
7import { AuthService } from '../../core'
8import {
9 FormReactive,
10 VIDEO_NAME,
11 VIDEO_CATEGORY,
12 VIDEO_LICENCE,
13 VIDEO_LANGUAGE,
14 VIDEO_DESCRIPTION,
15 VIDEO_TAGS
16} from '../../shared'
17import { Video, VideoService } from '../shared'
18
19@Component({
20 selector: 'my-videos-update',
21 styleUrls: [ './video-edit.component.scss' ],
22 templateUrl: './video-update.component.html'
23})
24
25export class VideoUpdateComponent extends FormReactive implements OnInit {
26 tags: string[] = []
27 videoCategories = []
28 videoLicences = []
29 videoLanguages = []
30 video: Video
31
32 tagValidators = VIDEO_TAGS.VALIDATORS
33 tagValidatorsMessages = VIDEO_TAGS.MESSAGES
34
35 error: string = null
36 form: FormGroup
37 formErrors = {
38 name: '',
39 category: '',
40 licence: '',
41 language: '',
42 description: ''
43 }
44 validationMessages = {
45 name: VIDEO_NAME.MESSAGES,
46 category: VIDEO_CATEGORY.MESSAGES,
47 licence: VIDEO_LICENCE.MESSAGES,
48 language: VIDEO_LANGUAGE.MESSAGES,
49 description: VIDEO_DESCRIPTION.MESSAGES
50 }
51
52 fileError = ''
53
54 constructor (
55 private authService: AuthService,
56 private elementRef: ElementRef,
57 private formBuilder: FormBuilder,
58 private route: ActivatedRoute,
59 private router: Router,
60 private notificationsService: NotificationsService,
61 private videoService: VideoService
62 ) {
63 super()
64 }
65
66 buildForm () {
67 this.form = this.formBuilder.group({
68 name: [ '', VIDEO_NAME.VALIDATORS ],
69 nsfw: [ false ],
70 category: [ '', VIDEO_CATEGORY.VALIDATORS ],
71 licence: [ '', VIDEO_LICENCE.VALIDATORS ],
72 language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
73 description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
74 tags: [ '' ]
75 })
76
77 this.form.valueChanges.subscribe(data => this.onValueChanged(data))
78 }
79
80 ngOnInit () {
81 this.buildForm()
82
83 this.videoCategories = this.videoService.videoCategories
84 this.videoLicences = this.videoService.videoLicences
85 this.videoLanguages = this.videoService.videoLanguages
86
87 const uuid: string = this.route.snapshot.params['uuid']
88 this.videoService.getVideo(uuid)
89 .subscribe(
90 video => {
91 this.video = video
92
93 this.hydrateFormFromVideo()
94 },
95
96 err => {
97 console.error(err)
98 this.error = 'Cannot fetch video.'
99 }
100 )
101 }
102
103 checkForm () {
104 this.forceCheck()
105
106 return this.form.valid
107 }
108
109 update () {
110 if (this.checkForm() === false) {
111 return
112 }
113
114 this.video.patch(this.form.value)
115
116 this.videoService.updateVideo(this.video)
117 .subscribe(
118 () => {
119 this.notificationsService.success('Success', 'Video updated.')
120 this.router.navigate([ '/videos/watch', this.video.uuid ])
121 },
122
123 err => {
124 this.error = 'Cannot update the video.'
125 console.error(err)
126 }
127 )
128
129 }
130
131 private hydrateFormFromVideo () {
132 this.form.patchValue(this.video.toJSON())
133 }
134}
diff --git a/client/src/app/videos/+video-edit/video-update.module.ts b/client/src/app/videos/+video-edit/video-update.module.ts
new file mode 100644
index 000000000..eeb2e35e2
--- /dev/null
+++ b/client/src/app/videos/+video-edit/video-update.module.ts
@@ -0,0 +1,30 @@
1import { NgModule } from '@angular/core'
2
3import { TagInputModule } from 'ngx-chips'
4
5import { VideoUpdateRoutingModule } from './video-update-routing.module'
6import { VideoUpdateComponent } from './video-update.component'
7import { VideoService } from '../shared'
8import { SharedModule } from '../../shared'
9
10@NgModule({
11 imports: [
12 TagInputModule,
13
14 VideoUpdateRoutingModule,
15 SharedModule
16 ],
17
18 declarations: [
19 VideoUpdateComponent
20 ],
21
22 exports: [
23 VideoUpdateComponent
24 ],
25
26 providers: [
27 VideoService
28 ]
29})
30export class VideoUpdateModule { }