aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos/+video-edit/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/videos/+video-edit/shared')
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.html9
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.scss24
-rw-r--r--client/src/app/videos/+video-edit/shared/video-description.component.ts68
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.html86
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.scss148
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.ts83
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.module.ts11
7 files changed, 388 insertions, 41 deletions
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.html b/client/src/app/videos/+video-edit/shared/video-description.component.html
new file mode 100644
index 000000000..5d05467be
--- /dev/null
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.html
@@ -0,0 +1,9 @@
1<textarea
2 [(ngModel)]="description" (ngModelChange)="onModelChange()"
3 id="description" name="description">
4</textarea>
5
6<tabset #staticTabs class="previews">
7 <tab heading="Truncated description preview" [innerHTML]="truncatedDescriptionHTML"></tab>
8 <tab heading="Complete description preview" [innerHTML]="descriptionHTML"></tab>
9</tabset>
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.scss b/client/src/app/videos/+video-edit/shared/video-description.component.scss
new file mode 100644
index 000000000..2a4c8d189
--- /dev/null
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.scss
@@ -0,0 +1,24 @@
1textarea {
2 @include peertube-input-text(100%);
3
4 padding: 5px 15px;
5 font-size: 15px;
6 height: 150px;
7 margin-bottom: 15px;
8}
9
10/deep/ {
11 .nav-link {
12 display: flex !important;
13 align-items: center;
14 height: 30px !important;
15 padding: 0 15px !important;
16 }
17
18 .tab-content {
19 min-height: 75px;
20 padding: 15px;
21 font-size: 15px;
22 }
23}
24
diff --git a/client/src/app/videos/+video-edit/shared/video-description.component.ts b/client/src/app/videos/+video-edit/shared/video-description.component.ts
new file mode 100644
index 000000000..9b77a27e6
--- /dev/null
+++ b/client/src/app/videos/+video-edit/shared/video-description.component.ts
@@ -0,0 +1,68 @@
1import { Component, forwardRef, Input, OnInit } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { truncate } from 'lodash'
4import 'rxjs/add/operator/debounceTime'
5import 'rxjs/add/operator/distinctUntilChanged'
6import { Subject } from 'rxjs/Subject'
7import { MarkdownService } from '../../shared'
8
9@Component({
10 selector: 'my-video-description',
11 templateUrl: './video-description.component.html',
12 styleUrls: [ './video-description.component.scss' ],
13 providers: [
14 {
15 provide: NG_VALUE_ACCESSOR,
16 useExisting: forwardRef(() => VideoDescriptionComponent),
17 multi: true
18 }
19 ]
20})
21
22export class VideoDescriptionComponent implements ControlValueAccessor, OnInit {
23 @Input() description = ''
24 truncatedDescriptionHTML = ''
25 descriptionHTML = ''
26
27 private descriptionChanged = new Subject<string>()
28
29 constructor (private markdownService: MarkdownService) {}
30
31 ngOnInit () {
32 this.descriptionChanged
33 .debounceTime(150)
34 .distinctUntilChanged()
35 .subscribe(() => this.updateDescriptionPreviews())
36
37 this.descriptionChanged.next(this.description)
38 }
39
40 propagateChange = (_: any) => { /* empty */ }
41
42 writeValue (description: string) {
43 this.description = description
44
45 this.descriptionChanged.next(this.description)
46 }
47
48 registerOnChange (fn: (_: any) => void) {
49 this.propagateChange = fn
50 }
51
52 registerOnTouched () {
53 // Unused
54 }
55
56 onModelChange () {
57 this.propagateChange(this.description)
58
59 this.descriptionChanged.next(this.description)
60 }
61
62 private updateDescriptionPreviews () {
63 if (!this.description) return
64
65 this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 }))
66 this.descriptionHTML = this.markdownService.markdownToHTML(this.description)
67 }
68}
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html
new file mode 100644
index 000000000..8c071ce12
--- /dev/null
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html
@@ -0,0 +1,86 @@
1<div class="video-edit row" [formGroup]="form">
2
3 <div class="col-md-8">
4 <div class="form-group">
5 <label for="name">Title</label>
6 <input type="text" id="name" formControlName="name" />
7 <div *ngIf="formErrors.name" class="form-error">
8 {{ formErrors.name }}
9 </div>
10 </div>
11
12 <div class="form-group">
13 <label class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
14 <tag-input
15 [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
16 formControlName="tags" maxItems="5" modelAsStrings="true"
17 ></tag-input>
18 </div>
19
20 <div class="form-group">
21 <label for="description">Description</label>
22 <my-video-description formControlName="description"></my-video-description>
23
24 <div *ngIf="formErrors.description" class="form-error">
25 {{ formErrors.description }}
26 </div>
27 </div>
28 </div>
29
30 <div class="col-md-4">
31 <div class="form-group">
32 <label for="category">Category</label>
33 <select id="category" formControlName="category">
34 <option></option>
35 <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option>
36 </select>
37
38 <div *ngIf="formErrors.category" class="form-error">
39 {{ formErrors.category }}
40 </div>
41 </div>
42
43 <div class="form-group">
44 <label for="licence">Licence</label>
45 <select id="licence" formControlName="licence">
46 <option></option>
47 <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option>
48 </select>
49
50 <div *ngIf="formErrors.licence" class="form-error">
51 {{ formErrors.licence }}
52 </div>
53 </div>
54
55 <div class="form-group">
56 <label for="language">Language</label>
57 <select id="language" formControlName="language">
58 <option></option>
59 <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option>
60 </select>
61
62 <div *ngIf="formErrors.language" class="form-error">
63 {{ formErrors.language }}
64 </div>
65 </div>
66
67 <div class="form-group">
68 <label for="privacy">Privacy</label>
69 <select id="privacy" formControlName="privacy">
70
71 <option></option>
72 <option *ngFor="let privacy of videoPrivacies" [value]="privacy.id">{{ privacy.label }}</option>
73 </select>
74
75 <div *ngIf="formErrors.privacy" class="form-error">
76 {{ formErrors.privacy }}
77 </div>
78 </div>
79
80 <div class="form-group form-group-checkbox">
81 <input type="checkbox" id="nsfw" formControlName="nsfw" />
82 <label for="nsfw">This video contains mature or explicit content</label>
83 </div>
84
85 </div>
86</div>
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.scss b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
index 9ee0c520c..d363499ce 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.scss
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.scss
@@ -1,48 +1,126 @@
1.btn-file { 1.video-edit {
2 position: relative; 2 height: 100%;
3 overflow: hidden; 3
4 display: block; 4 .form-group {
5 margin-bottom: 25px;
6 }
7
8 input {
9 @include peertube-input-text(100%);
10 display: block;
11
12 &[type=checkbox] {
13 outline: 0;
14 }
15 }
16
17 select {
18 @include peertube-select(100%);
19 }
20
21 input, select {
22 font-size: 15px
23 }
24
25 .form-group-checkbox {
26 display: flex;
27 align-items: center;
28
29 label {
30 font-weight: $font-regular;
31 margin: 0;
32 }
33
34 input {
35 width: 10px;
36 margin-right: 10px;
37 }
38 }
5} 39}
6 40
7.btn-file input[type=file] { 41.submit-container {
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; 42 text-align: right;
15 filter: alpha(opacity=0); 43 position: relative;
16 opacity: 0; 44 bottom: $button-height;
17 outline: none;
18 background: white;
19 cursor: inherit;
20 display: block;
21}
22 45
23.form-group { 46 .message-submit {
24 margin-bottom: 10px; 47 display: inline-block;
25} 48 margin-right: 25px;
49
50 color: #585858;
51 font-size: 15px;
52 }
53
54 .submit-button {
55 @include peertube-button;
56 @include orange-button;
57
58 display: inline-block;
26 59
27div.tags { 60 input {
28 height: 40px; 61 cursor: inherit;
29 font-size: 20px; 62 background-color: inherit;
30 margin-top: 20px; 63 border: none;
64 padding: 0;
65 outline: 0;
66 }
31 67
32 .tag { 68 .icon.icon-validate {
33 margin-right: 10px; 69 @include icon(20px);
34 70
35 .remove { 71 cursor: inherit;
36 cursor: pointer; 72 position: relative;
73 top: -1px;
74 margin-right: 4px;
75 background-image: url('../../../../assets/images/global/validate.svg');
37 } 76 }
38 } 77 }
39} 78}
40 79
41div.file-to-upload { 80/deep/ {
42 height: 40px; 81 .ng2-tag-input {
82 border: none !important;
83 }
43 84
44 .glyphicon-remove { 85 .ng2-tags-container {
45 cursor: pointer; 86 display: flex;
87 align-items: center;
88 border: 1px solid #C6C6C6;
89 border-radius: 3px;
90 padding: 5px !important;
91 }
92
93 tag {
94 background-color: #E5E5E5 !important;
95 border-radius: 3px !important;
96 font-size: 15px !important;
97 color: #000 !important;
98 height: 30px !important;
99 line-height: 30px !important;
100 margin: 0 5px 0 0 !important;
101 cursor: default !important;
102 padding: 0 8px 0 10px !important;
103
104 div {
105 height: 100% !important;
106 }
107 }
108
109 delete-icon {
110 cursor: pointer !important;
111 height: auto !important;
112 vertical-align: middle !important;
113 padding-left: 6px !important;
114
115 svg {
116 height: auto !important;
117 vertical-align: middle !important;
118 fill: #585858 !important;
119 }
120
121 &:hover {
122 transform: none !important;
123 }
46 } 124 }
47} 125}
48 126
@@ -50,7 +128,3 @@ div.file-to-upload {
50 font-size: 0.8em; 128 font-size: 0.8em;
51 font-style: italic; 129 font-style: italic;
52} 130}
53
54.label-tags {
55 margin-bottom: 0;
56}
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.ts b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
new file mode 100644
index 000000000..5b1cc3f9c
--- /dev/null
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
@@ -0,0 +1,83 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { FormBuilder, FormControl, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router'
4import { NotificationsService } from 'angular2-notifications'
5import { ServerService } from 'app/core'
6import { VideoEdit } from 'app/shared/video/video-edit.model'
7import 'rxjs/add/observable/forkJoin'
8import { VideoPrivacy } from '../../../../../shared/models/videos/video-privacy.enum'
9import {
10 ValidatorMessage,
11 VIDEO_CATEGORY,
12 VIDEO_DESCRIPTION,
13 VIDEO_LANGUAGE,
14 VIDEO_LICENCE,
15 VIDEO_NAME,
16 VIDEO_PRIVACY,
17 VIDEO_TAGS
18} from '../../../shared/forms/form-validators'
19
20@Component({
21 selector: 'my-video-edit',
22 styleUrls: [ './video-edit.component.scss' ],
23 templateUrl: './video-edit.component.html'
24})
25
26export class VideoEditComponent implements OnInit {
27 @Input() form: FormGroup
28 @Input() formErrors: { [ id: string ]: string } = {}
29 @Input() validationMessages: ValidatorMessage = {}
30 @Input() videoPrivacies = []
31
32 tags: string[] = []
33 videoCategories = []
34 videoLicences = []
35 videoLanguages = []
36 video: VideoEdit
37
38 tagValidators = VIDEO_TAGS.VALIDATORS
39 tagValidatorsMessages = VIDEO_TAGS.MESSAGES
40
41 error: string = null
42
43 constructor (
44 private formBuilder: FormBuilder,
45 private route: ActivatedRoute,
46 private router: Router,
47 private notificationsService: NotificationsService,
48 private serverService: ServerService
49 ) { }
50
51 updateForm () {
52 this.formErrors['name'] = ''
53 this.formErrors['privacy'] = ''
54 this.formErrors['category'] = ''
55 this.formErrors['licence'] = ''
56 this.formErrors['language'] = ''
57 this.formErrors['description'] = ''
58
59 this.validationMessages['name'] = VIDEO_NAME.MESSAGES
60 this.validationMessages['privacy'] = VIDEO_PRIVACY.MESSAGES
61 this.validationMessages['category'] = VIDEO_CATEGORY.MESSAGES
62 this.validationMessages['licence'] = VIDEO_LICENCE.MESSAGES
63 this.validationMessages['language'] = VIDEO_LANGUAGE.MESSAGES
64 this.validationMessages['description'] = VIDEO_DESCRIPTION.MESSAGES
65
66 this.form.addControl('name', new FormControl('', VIDEO_NAME.VALIDATORS))
67 this.form.addControl('privacy', new FormControl('', VIDEO_PRIVACY.VALIDATORS))
68 this.form.addControl('nsfw', new FormControl(false))
69 this.form.addControl('category', new FormControl('', VIDEO_CATEGORY.VALIDATORS))
70 this.form.addControl('licence', new FormControl('', VIDEO_LICENCE.VALIDATORS))
71 this.form.addControl('language', new FormControl('', VIDEO_LANGUAGE.VALIDATORS))
72 this.form.addControl('description', new FormControl('', VIDEO_DESCRIPTION.VALIDATORS))
73 this.form.addControl('tags', new FormControl(''))
74 }
75
76 ngOnInit () {
77 this.updateForm()
78
79 this.videoCategories = this.serverService.getVideoCategories()
80 this.videoLicences = this.serverService.getVideoLicences()
81 this.videoLanguages = this.serverService.getVideoLanguages()
82 }
83}
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.module.ts b/client/src/app/videos/+video-edit/shared/video-edit.module.ts
index c64cea920..ce106d82f 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.module.ts
+++ b/client/src/app/videos/+video-edit/shared/video-edit.module.ts
@@ -3,8 +3,10 @@ import { NgModule } from '@angular/core'
3import { TagInputModule } from 'ngx-chips' 3import { TagInputModule } from 'ngx-chips'
4import { TabsModule } from 'ngx-bootstrap/tabs' 4import { TabsModule } from 'ngx-bootstrap/tabs'
5 5
6import { VideoService, MarkdownService, VideoDescriptionComponent } from '../../shared' 6import { MarkdownService } from '../../shared'
7import { SharedModule } from '../../../shared' 7import { SharedModule } from '../../../shared'
8import { VideoDescriptionComponent } from './video-description.component'
9import { VideoEditComponent } from './video-edit.component'
8 10
9@NgModule({ 11@NgModule({
10 imports: [ 12 imports: [
@@ -15,18 +17,19 @@ import { SharedModule } from '../../../shared'
15 ], 17 ],
16 18
17 declarations: [ 19 declarations: [
18 VideoDescriptionComponent 20 VideoDescriptionComponent,
21 VideoEditComponent
19 ], 22 ],
20 23
21 exports: [ 24 exports: [
22 TagInputModule, 25 TagInputModule,
23 TabsModule, 26 TabsModule,
24 27
25 VideoDescriptionComponent 28 VideoDescriptionComponent,
29 VideoEditComponent
26 ], 30 ],
27 31
28 providers: [ 32 providers: [
29 VideoService,
30 MarkdownService 33 MarkdownService
31 ] 34 ]
32}) 35})