diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-11-27 18:10:26 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-11-27 18:10:26 +0100 |
commit | bf57d5eebf8b0fa2361b7973ce9772abd1bb4828 (patch) | |
tree | 6f8ba86f2bedf8bb630c5f0cef4fbce88c2abf76 /client/src | |
parent | 447fde277497dfff73310dc12bf79fb576139b94 (diff) | |
download | PeerTube-bf57d5eebf8b0fa2361b7973ce9772abd1bb4828.tar.gz PeerTube-bf57d5eebf8b0fa2361b7973ce9772abd1bb4828.tar.zst PeerTube-bf57d5eebf8b0fa2361b7973ce9772abd1bb4828.zip |
Client: try to improve ux for the upload form
Diffstat (limited to 'client/src')
4 files changed, 57 insertions, 28 deletions
diff --git a/client/src/app/shared/forms/form-reactive.ts b/client/src/app/shared/forms/form-reactive.ts index 1e8a69771..a5732e083 100644 --- a/client/src/app/shared/forms/form-reactive.ts +++ b/client/src/app/shared/forms/form-reactive.ts | |||
@@ -21,4 +21,20 @@ export abstract class FormReactive { | |||
21 | } | 21 | } |
22 | } | 22 | } |
23 | } | 23 | } |
24 | |||
25 | // Same as onValueChanged but force checking even if the field is not dirty | ||
26 | protected forceCheck() { | ||
27 | for (const field in this.formErrors) { | ||
28 | // clear previous error message (if any) | ||
29 | this.formErrors[field] = ''; | ||
30 | const control = this.form.get(field); | ||
31 | |||
32 | if (control && !control.valid) { | ||
33 | const messages = this.validationMessages[field]; | ||
34 | for (const key in control.errors) { | ||
35 | this.formErrors[field] += messages[key] + ' '; | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | } | ||
24 | } | 40 | } |
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 14c7a0136..b6be0d782 100644 --- a/client/src/app/videos/video-add/video-add.component.html +++ b/client/src/app/videos/video-add/video-add.component.html | |||
@@ -15,7 +15,7 @@ | |||
15 | </div> | 15 | </div> |
16 | 16 | ||
17 | <div class="form-group"> | 17 | <div class="form-group"> |
18 | <label for="tags">Tags</label> | 18 | <label for="tags">Tags</label> <span class="little-information">(press enter to add the tag)</span> |
19 | <input | 19 | <input |
20 | type="text" class="form-control" id="currentTag" | 20 | type="text" class="form-control" id="currentTag" |
21 | formControlName="currentTag" (keyup)="onTagKeyPress($event)" | 21 | formControlName="currentTag" (keyup)="onTagKeyPress($event)" |
@@ -32,6 +32,10 @@ | |||
32 | </div> | 32 | </div> |
33 | </div> | 33 | </div> |
34 | 34 | ||
35 | <div *ngIf="tagsError" class="alert alert-danger"> | ||
36 | {{ tagsError }} | ||
37 | </div> | ||
38 | |||
35 | <div class="form-group"> | 39 | <div class="form-group"> |
36 | <label for="videofile">File</label> | 40 | <label for="videofile">File</label> |
37 | <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" > | 41 | <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" > |
@@ -39,6 +43,7 @@ | |||
39 | <input | 43 | <input |
40 | type="file" name="videofile" id="videofile" | 44 | type="file" name="videofile" id="videofile" |
41 | ng2FileSelect [uploader]="uploader" [disabled]="filename !== null" | 45 | ng2FileSelect [uploader]="uploader" [disabled]="filename !== null" |
46 | (change)="fileChanged()" | ||
42 | > | 47 | > |
43 | </div> | 48 | </div> |
44 | </div> | 49 | </div> |
@@ -50,6 +55,10 @@ | |||
50 | </div> | 55 | </div> |
51 | </div> | 56 | </div> |
52 | 57 | ||
58 | <div *ngIf="fileError" class="alert alert-danger"> | ||
59 | {{ fileError }} | ||
60 | </div> | ||
61 | |||
53 | <div class="form-group"> | 62 | <div class="form-group"> |
54 | <label for="description">Description</label> | 63 | <label for="description">Description</label> |
55 | <textarea | 64 | <textarea |
@@ -69,7 +78,6 @@ | |||
69 | <div class="form-group"> | 78 | <div class="form-group"> |
70 | <input | 79 | <input |
71 | type="button" value="Upload" class="btn btn-default form-control" | 80 | type="button" value="Upload" class="btn btn-default form-control" |
72 | [title]="getInvalidFieldsTitle()" [disabled]="!form.valid || tags.length === 0 || filename === null" | ||
73 | (click)="upload()" | 81 | (click)="upload()" |
74 | > | 82 | > |
75 | </div> | 83 | </div> |
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 d66df2fd4..11ee3297e 100644 --- a/client/src/app/videos/video-add/video-add.component.scss +++ b/client/src/app/videos/video-add/video-add.component.scss | |||
@@ -51,6 +51,7 @@ div.file-to-upload { | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | div.progress { | 54 | .little-information { |
55 | // height: 40px; | 55 | font-size: 0.8em; |
56 | font-style: italic; | ||
56 | } | 57 | } |
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 6eab54f7e..1e700ae48 100644 --- a/client/src/app/videos/video-add/video-add.component.ts +++ b/client/src/app/videos/video-add/video-add.component.ts | |||
@@ -30,6 +30,10 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
30 | currentTag: VIDEO_TAGS.MESSAGES | 30 | currentTag: VIDEO_TAGS.MESSAGES |
31 | }; | 31 | }; |
32 | 32 | ||
33 | // Special error messages | ||
34 | tagsError = ''; | ||
35 | fileError = ''; | ||
36 | |||
33 | constructor( | 37 | constructor( |
34 | private authService: AuthService, | 38 | private authService: AuthService, |
35 | private elementRef: ElementRef, | 39 | private elementRef: ElementRef, |
@@ -57,30 +61,6 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
57 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 61 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); |
58 | } | 62 | } |
59 | 63 | ||
60 | getInvalidFieldsTitle() { | ||
61 | let title = ''; | ||
62 | const nameControl = this.form.controls['name']; | ||
63 | const descriptionControl = this.form.controls['description']; | ||
64 | |||
65 | if (!nameControl.valid) { | ||
66 | title += 'A name is required\n'; | ||
67 | } | ||
68 | |||
69 | if (this.tags.length === 0) { | ||
70 | title += 'At least one tag is required\n'; | ||
71 | } | ||
72 | |||
73 | if (this.filename === null) { | ||
74 | title += 'A file is required\n'; | ||
75 | } | ||
76 | |||
77 | if (!descriptionControl.valid) { | ||
78 | title += 'A description is required\n'; | ||
79 | } | ||
80 | |||
81 | return title; | ||
82 | } | ||
83 | |||
84 | ngOnInit() { | 64 | ngOnInit() { |
85 | this.uploader = new FileUploader({ | 65 | this.uploader = new FileUploader({ |
86 | authToken: this.authService.getRequestHeaderValue(), | 66 | authToken: this.authService.getRequestHeaderValue(), |
@@ -104,6 +84,24 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
104 | this.buildForm(); | 84 | this.buildForm(); |
105 | } | 85 | } |
106 | 86 | ||
87 | checkForm() { | ||
88 | this.forceCheck(); | ||
89 | |||
90 | if (this.tags.length === 0) { | ||
91 | this.tagsError = 'You have 0 tags'; | ||
92 | } | ||
93 | |||
94 | if (this.filename === null) { | ||
95 | this.fileError = 'You did not add a file.'; | ||
96 | } | ||
97 | |||
98 | return this.form.valid === true && this.tagsError === '' && this.fileError === ''; | ||
99 | } | ||
100 | |||
101 | fileChanged() { | ||
102 | this.fileError = ''; | ||
103 | } | ||
104 | |||
107 | onTagKeyPress(event: KeyboardEvent) { | 105 | onTagKeyPress(event: KeyboardEvent) { |
108 | const currentTag = this.form.value['currentTag']; | 106 | const currentTag = this.form.value['currentTag']; |
109 | 107 | ||
@@ -121,6 +119,8 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
121 | if (this.tags.length >= 3) { | 119 | if (this.tags.length >= 3) { |
122 | this.form.get('currentTag').disable(); | 120 | this.form.get('currentTag').disable(); |
123 | } | 121 | } |
122 | |||
123 | this.tagsError = ''; | ||
124 | } | 124 | } |
125 | } | 125 | } |
126 | } | 126 | } |
@@ -135,6 +135,10 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | upload() { | 137 | upload() { |
138 | if (this.checkForm() === false) { | ||
139 | return; | ||
140 | } | ||
141 | |||
138 | const item = this.uploader.queue[0]; | 142 | const item = this.uploader.queue[0]; |
139 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 | 143 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 |
140 | item.alias = 'videofile'; | 144 | item.alias = 'videofile'; |