diff options
author | Chocobozzz <me@florianbigard.com> | 2020-08-11 16:07:53 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2020-08-11 16:18:42 +0200 |
commit | 52c4976fcf4ee255a3af68ff9778e4f5c4f84bd4 (patch) | |
tree | 887d2b6106548ad23cf016d82baf1977198027d9 /client/src/app/shared | |
parent | 3d25d5de33d8aa0ba00d7514522b25d22bf0e0a1 (diff) | |
download | PeerTube-52c4976fcf4ee255a3af68ff9778e4f5c4f84bd4.tar.gz PeerTube-52c4976fcf4ee255a3af68ff9778e4f5c4f84bd4.tar.zst PeerTube-52c4976fcf4ee255a3af68ff9778e4f5c4f84bd4.zip |
Use ng select for multiselect
Diffstat (limited to 'client/src/app/shared')
18 files changed, 228 insertions, 58 deletions
diff --git a/client/src/app/shared/shared-forms/index.ts b/client/src/app/shared/shared-forms/index.ts index aa0ee015a..747df65cf 100644 --- a/client/src/app/shared/shared-forms/index.ts +++ b/client/src/app/shared/shared-forms/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | export * from './form-validators' | 1 | export * from './form-validators' |
2 | export * from './form-reactive' | 2 | export * from './form-reactive' |
3 | export * from './select' | ||
3 | export * from './input-readonly-copy.component' | 4 | export * from './input-readonly-copy.component' |
4 | export * from './markdown-textarea.component' | 5 | export * from './markdown-textarea.component' |
5 | export * from './peertube-checkbox.component' | 6 | export * from './peertube-checkbox.component' |
diff --git a/client/src/app/shared/shared-forms/select-shared.component.scss b/client/src/app/shared/shared-forms/select-shared.component.scss deleted file mode 100644 index 4f231d28a..000000000 --- a/client/src/app/shared/shared-forms/select-shared.component.scss +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | $width-size: auto; | ||
2 | |||
3 | ng-select { | ||
4 | width: $width-size; | ||
5 | @media screen and (max-width: $width-size) { | ||
6 | width: 100%; | ||
7 | } | ||
8 | } | ||
9 | |||
10 | // make sure the image is vertically adjusted | ||
11 | ng-select ::ng-deep .ng-value-label img { | ||
12 | position: relative; | ||
13 | top: -1px; | ||
14 | } | ||
15 | |||
16 | ng-select ::ng-deep img { | ||
17 | border-radius: 50%; | ||
18 | height: 20px; | ||
19 | width: 20px; | ||
20 | } | ||
diff --git a/client/src/app/shared/shared-forms/select/index.ts b/client/src/app/shared/shared-forms/select/index.ts new file mode 100644 index 000000000..33459b23b --- /dev/null +++ b/client/src/app/shared/shared-forms/select/index.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export * from './select-channel.component' | ||
2 | export * from './select-options.component' | ||
3 | export * from './select-tags.component' | ||
4 | export * from './select-checkbox.component' | ||
diff --git a/client/src/app/shared/shared-forms/select-channel.component.html b/client/src/app/shared/shared-forms/select/select-channel.component.html index 897d13ee7..897d13ee7 100644 --- a/client/src/app/shared/shared-forms/select-channel.component.html +++ b/client/src/app/shared/shared-forms/select/select-channel.component.html | |||
diff --git a/client/src/app/shared/shared-forms/select-channel.component.ts b/client/src/app/shared/shared-forms/select/select-channel.component.ts index ef4192095..1b0db9b6f 100644 --- a/client/src/app/shared/shared-forms/select-channel.component.ts +++ b/client/src/app/shared/shared-forms/select/select-channel.component.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Component, forwardRef, Input } from '@angular/core' | 1 | import { Component, forwardRef, Input } from '@angular/core' |
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' |
3 | import { Actor } from '../shared-main' | 3 | import { Actor } from '@app/shared/shared-main/account/actor.model' |
4 | 4 | ||
5 | export type SelectChannelItem = { | 5 | export type SelectChannelItem = { |
6 | id: number | 6 | id: number |
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.html b/client/src/app/shared/shared-forms/select/select-checkbox.component.html new file mode 100644 index 000000000..3f81dd152 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.html | |||
@@ -0,0 +1,41 @@ | |||
1 | <ng-select | ||
2 | [items]="availableItems" | ||
3 | [(ngModel)]="selectedItems" | ||
4 | (ngModelChange)="onModelChange()" | ||
5 | i18n-placeholder placeholder="Add a new language" | ||
6 | [clearable]="true" | ||
7 | [multiple]="true" | ||
8 | [searchable]="true" | ||
9 | [closeOnSelect]="false" | ||
10 | |||
11 | bindValue="id" | ||
12 | bindLabel="label" | ||
13 | |||
14 | notFoundText="No items found" i18n-notFoundText | ||
15 | |||
16 | [selectableGroup]="selectableGroup" | ||
17 | [selectableGroupAsModel]="selectableGroupAsModel" | ||
18 | |||
19 | groupBy="group" | ||
20 | [compareWith]="compareFn" | ||
21 | |||
22 | [maxSelectedItems]="maxSelectedItems" | ||
23 | > | ||
24 | |||
25 | <ng-template ng-optgroup-tmp let-item="item" let-item$="item$" let-index="index"> | ||
26 | <div class="form-group-checkbox"> | ||
27 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> | ||
28 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> | ||
29 | <span>{{ item.group }}</span> | ||
30 | </div> | ||
31 | </ng-template> | ||
32 | |||
33 | <ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index"> | ||
34 | <div class="form-group-checkbox"> | ||
35 | <input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/> | ||
36 | <span role="checkbox" [attr.aria-checked]="item$.selected"></span> | ||
37 | <span>{{ item.label }}</span> | ||
38 | </div> | ||
39 | </ng-template> | ||
40 | |||
41 | </ng-select> | ||
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.scss b/client/src/app/shared/shared-forms/select/select-checkbox.component.scss new file mode 100644 index 000000000..145f6b26c --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.scss | |||
@@ -0,0 +1,18 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | ng-select ::ng-deep { | ||
5 | .ng-option { | ||
6 | display: flex; | ||
7 | align-items: center; | ||
8 | } | ||
9 | |||
10 | .form-group-checkbox { | ||
11 | display: flex; | ||
12 | align-items: center; | ||
13 | |||
14 | input { | ||
15 | @include peertube-checkbox(1px); | ||
16 | } | ||
17 | } | ||
18 | } | ||
diff --git a/client/src/app/shared/shared-forms/select/select-checkbox.component.ts b/client/src/app/shared/shared-forms/select/select-checkbox.component.ts new file mode 100644 index 000000000..93653fef1 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.ts | |||
@@ -0,0 +1,75 @@ | |||
1 | import { Component, Input, forwardRef } from '@angular/core' | ||
2 | import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms' | ||
3 | import { SelectOptionsItem } from './select-options.component' | ||
4 | |||
5 | export type ItemSelectCheckboxValue = { id?: string | number, group?: string } | string | ||
6 | |||
7 | @Component({ | ||
8 | selector: 'my-select-checkbox', | ||
9 | styleUrls: [ './select-shared.component.scss', 'select-checkbox.component.scss' ], | ||
10 | templateUrl: './select-checkbox.component.html', | ||
11 | providers: [ | ||
12 | { | ||
13 | provide: NG_VALUE_ACCESSOR, | ||
14 | useExisting: forwardRef(() => SelectCheckboxComponent), | ||
15 | multi: true | ||
16 | } | ||
17 | ] | ||
18 | }) | ||
19 | export class SelectCheckboxComponent implements ControlValueAccessor { | ||
20 | @Input() availableItems: SelectOptionsItem[] = [] | ||
21 | @Input() selectedItems: ItemSelectCheckboxValue[] = [] | ||
22 | @Input() selectableGroup: boolean | ||
23 | @Input() selectableGroupAsModel: boolean | ||
24 | @Input() maxSelectedItems: number | ||
25 | |||
26 | propagateChange = (_: any) => { /* empty */ } | ||
27 | |||
28 | writeValue (items: ItemSelectCheckboxValue[]) { | ||
29 | if (Array.isArray(items)) { | ||
30 | this.selectedItems = items.map(i => { | ||
31 | if (typeof i === 'string' || typeof i === 'number') { | ||
32 | return i + '' | ||
33 | } | ||
34 | |||
35 | if (i.group) { | ||
36 | return { group: i.group } | ||
37 | } | ||
38 | |||
39 | return { id: i.id + '' } | ||
40 | }) | ||
41 | } else { | ||
42 | this.selectedItems = items | ||
43 | } | ||
44 | |||
45 | this.propagateChange(this.selectedItems) | ||
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.selectedItems) | ||
58 | } | ||
59 | |||
60 | compareFn (item: SelectOptionsItem, selected: ItemSelectCheckboxValue) { | ||
61 | if (typeof selected === 'string') { | ||
62 | return item.id === selected | ||
63 | } | ||
64 | |||
65 | if (this.selectableGroup && item.group && selected.group) { | ||
66 | return item.group === selected.group | ||
67 | } | ||
68 | |||
69 | if (selected.id && item.id) { | ||
70 | return item.id === selected.id | ||
71 | } | ||
72 | |||
73 | return false | ||
74 | } | ||
75 | } | ||
diff --git a/client/src/app/shared/shared-forms/select-options.component.html b/client/src/app/shared/shared-forms/select/select-options.component.html index fda0c2c56..48eca1cf5 100644 --- a/client/src/app/shared/shared-forms/select-options.component.html +++ b/client/src/app/shared/shared-forms/select/select-options.component.html | |||
@@ -3,10 +3,11 @@ | |||
3 | [groupBy]="groupBy" | 3 | [groupBy]="groupBy" |
4 | [(ngModel)]="selectedId" | 4 | [(ngModel)]="selectedId" |
5 | (ngModelChange)="onModelChange()" | 5 | (ngModelChange)="onModelChange()" |
6 | [bindLabel]="bindLabel" | ||
7 | [bindValue]="bindValue" | ||
8 | [clearable]="clearable" | 6 | [clearable]="clearable" |
9 | [searchable]="searchable" | 7 | [searchable]="searchable" |
8 | |||
9 | bindLabel="label" | ||
10 | bindValue="id" | ||
10 | > | 11 | > |
11 | <ng-template ng-option-tmp let-item="item" let-index="index"> | 12 | <ng-template ng-option-tmp let-item="item" let-index="index"> |
12 | {{ item.label }} | 13 | {{ item.label }} |
diff --git a/client/src/app/shared/shared-forms/select-options.component.ts b/client/src/app/shared/shared-forms/select/select-options.component.ts index 09f7df53b..3ba24c732 100644 --- a/client/src/app/shared/shared-forms/select-options.component.ts +++ b/client/src/app/shared/shared-forms/select/select-options.component.ts | |||
@@ -1,7 +1,13 @@ | |||
1 | import { Component, Input, forwardRef } from '@angular/core' | 1 | import { Component, Input, forwardRef } from '@angular/core' |
2 | import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms' | 2 | import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms' |
3 | 3 | ||
4 | export type SelectOptionsItem = { id: number | string, label: string, description?: string } | 4 | export type SelectOptionsItem = { |
5 | id: string | number | ||
6 | label: string | ||
7 | description?: string | ||
8 | group?: string | ||
9 | groupLabel?: string | ||
10 | } | ||
5 | 11 | ||
6 | @Component({ | 12 | @Component({ |
7 | selector: 'my-select-options', | 13 | selector: 'my-select-options', |
@@ -19,14 +25,10 @@ export class SelectOptionsComponent implements ControlValueAccessor { | |||
19 | @Input() items: SelectOptionsItem[] = [] | 25 | @Input() items: SelectOptionsItem[] = [] |
20 | @Input() clearable = false | 26 | @Input() clearable = false |
21 | @Input() searchable = false | 27 | @Input() searchable = false |
22 | @Input() bindValue = 'id' | ||
23 | @Input() groupBy: string | 28 | @Input() groupBy: string |
24 | 29 | ||
25 | selectedId: number | string | 30 | selectedId: number | string |
26 | 31 | ||
27 | // ng-select options | ||
28 | bindLabel = 'label' | ||
29 | |||
30 | propagateChange = (_: any) => { /* empty */ } | 32 | propagateChange = (_: any) => { /* empty */ } |
31 | 33 | ||
32 | writeValue (id: number | string) { | 34 | writeValue (id: number | string) { |
diff --git a/client/src/app/shared/shared-forms/select/select-shared.component.scss b/client/src/app/shared/shared-forms/select/select-shared.component.scss new file mode 100644 index 000000000..0b4c6b784 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-shared.component.scss | |||
@@ -0,0 +1,32 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | $form-base-input-width: auto; | ||
5 | |||
6 | ng-select { | ||
7 | width: $form-base-input-width; | ||
8 | |||
9 | @media screen and (max-width: $form-base-input-width) { | ||
10 | width: 100%; | ||
11 | } | ||
12 | } | ||
13 | |||
14 | ng-select ::ng-deep { | ||
15 | .ng-value-container { | ||
16 | max-height: 100px; | ||
17 | overflow-y: auto; | ||
18 | overflow-x: hidden; | ||
19 | } | ||
20 | |||
21 | // make sure the image is vertically adjusted | ||
22 | .ng-value-label img { | ||
23 | position: relative; | ||
24 | top: -1px; | ||
25 | } | ||
26 | |||
27 | img { | ||
28 | border-radius: 50%; | ||
29 | height: 20px; | ||
30 | width: 20px; | ||
31 | } | ||
32 | } | ||
diff --git a/client/src/app/shared/shared-forms/select-tags.component.html b/client/src/app/shared/shared-forms/select/select-tags.component.html index e1cd50882..e1cd50882 100644 --- a/client/src/app/shared/shared-forms/select-tags.component.html +++ b/client/src/app/shared/shared-forms/select/select-tags.component.html | |||
diff --git a/client/src/app/shared/shared-forms/select-tags.component.scss b/client/src/app/shared/shared-forms/select/select-tags.component.scss index ad76bc7ee..ad76bc7ee 100644 --- a/client/src/app/shared/shared-forms/select-tags.component.scss +++ b/client/src/app/shared/shared-forms/select/select-tags.component.scss | |||
diff --git a/client/src/app/shared/shared-forms/select-tags.component.ts b/client/src/app/shared/shared-forms/select/select-tags.component.ts index a8a19d788..93d199037 100644 --- a/client/src/app/shared/shared-forms/select-tags.component.ts +++ b/client/src/app/shared/shared-forms/select/select-tags.component.ts | |||
@@ -33,8 +33,6 @@ export class SelectTagsComponent implements ControlValueAccessor { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | onModelChange () { | 35 | onModelChange () { |
36 | console.log(this.selectedItems) | ||
37 | |||
38 | this.propagateChange(this.selectedItems) | 36 | this.propagateChange(this.selectedItems) |
39 | } | 37 | } |
40 | } | 38 | } |
diff --git a/client/src/app/shared/shared-forms/shared-form.module.ts b/client/src/app/shared/shared-forms/shared-form.module.ts index ea6270083..0e0ed5bab 100644 --- a/client/src/app/shared/shared-forms/shared-form.module.ts +++ b/client/src/app/shared/shared-forms/shared-form.module.ts | |||
@@ -3,7 +3,6 @@ import { NgModule } from '@angular/core' | |||
3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' | 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' |
4 | import { InputMaskModule } from 'primeng/inputmask' | 4 | import { InputMaskModule } from 'primeng/inputmask' |
5 | import { InputSwitchModule } from 'primeng/inputswitch' | 5 | import { InputSwitchModule } from 'primeng/inputswitch' |
6 | import { MultiSelectModule } from 'primeng/multiselect' | ||
7 | import { NgSelectModule } from '@ng-select/ng-select' | 6 | import { NgSelectModule } from '@ng-select/ng-select' |
8 | import { BatchDomainsValidatorsService } from '@app/shared/shared-forms/form-validators/batch-domains-validators.service' | 7 | import { BatchDomainsValidatorsService } from '@app/shared/shared-forms/form-validators/batch-domains-validators.service' |
9 | import { SharedGlobalIconModule } from '../shared-icons' | 8 | import { SharedGlobalIconModule } from '../shared-icons' |
@@ -32,9 +31,7 @@ import { PreviewUploadComponent } from './preview-upload.component' | |||
32 | import { ReactiveFileComponent } from './reactive-file.component' | 31 | import { ReactiveFileComponent } from './reactive-file.component' |
33 | import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' | 32 | import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' |
34 | import { TimestampInputComponent } from './timestamp-input.component' | 33 | import { TimestampInputComponent } from './timestamp-input.component' |
35 | import { SelectChannelComponent } from './select-channel.component' | 34 | import { SelectChannelComponent, SelectCheckboxComponent, SelectOptionsComponent, SelectTagsComponent } from './select' |
36 | import { SelectOptionsComponent } from './select-options.component' | ||
37 | import { SelectTagsComponent } from './select-tags.component' | ||
38 | 35 | ||
39 | @NgModule({ | 36 | @NgModule({ |
40 | imports: [ | 37 | imports: [ |
@@ -43,7 +40,6 @@ import { SelectTagsComponent } from './select-tags.component' | |||
43 | 40 | ||
44 | InputMaskModule, | 41 | InputMaskModule, |
45 | InputSwitchModule, | 42 | InputSwitchModule, |
46 | MultiSelectModule, | ||
47 | NgSelectModule, | 43 | NgSelectModule, |
48 | 44 | ||
49 | SharedMainModule, | 45 | SharedMainModule, |
@@ -58,9 +54,11 @@ import { SelectTagsComponent } from './select-tags.component' | |||
58 | ReactiveFileComponent, | 54 | ReactiveFileComponent, |
59 | TextareaAutoResizeDirective, | 55 | TextareaAutoResizeDirective, |
60 | TimestampInputComponent, | 56 | TimestampInputComponent, |
57 | |||
61 | SelectChannelComponent, | 58 | SelectChannelComponent, |
62 | SelectOptionsComponent, | 59 | SelectOptionsComponent, |
63 | SelectTagsComponent | 60 | SelectTagsComponent, |
61 | SelectCheckboxComponent | ||
64 | ], | 62 | ], |
65 | 63 | ||
66 | exports: [ | 64 | exports: [ |
@@ -69,7 +67,6 @@ import { SelectTagsComponent } from './select-tags.component' | |||
69 | 67 | ||
70 | InputMaskModule, | 68 | InputMaskModule, |
71 | InputSwitchModule, | 69 | InputSwitchModule, |
72 | MultiSelectModule, | ||
73 | NgSelectModule, | 70 | NgSelectModule, |
74 | 71 | ||
75 | InputReadonlyCopyComponent, | 72 | InputReadonlyCopyComponent, |
@@ -79,9 +76,11 @@ import { SelectTagsComponent } from './select-tags.component' | |||
79 | ReactiveFileComponent, | 76 | ReactiveFileComponent, |
80 | TextareaAutoResizeDirective, | 77 | TextareaAutoResizeDirective, |
81 | TimestampInputComponent, | 78 | TimestampInputComponent, |
79 | |||
82 | SelectChannelComponent, | 80 | SelectChannelComponent, |
83 | SelectOptionsComponent, | 81 | SelectOptionsComponent, |
84 | SelectTagsComponent | 82 | SelectTagsComponent, |
83 | SelectCheckboxComponent | ||
85 | ], | 84 | ], |
86 | 85 | ||
87 | providers: [ | 86 | providers: [ |
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.html b/client/src/app/shared/shared-user-settings/user-video-settings.component.html index bb9f59070..655b49e18 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.html +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.html | |||
@@ -30,11 +30,11 @@ | |||
30 | </my-help> | 30 | </my-help> |
31 | 31 | ||
32 | <div> | 32 | <div> |
33 | <p-multiSelect | 33 | <my-select-checkbox |
34 | inputId="videoLanguages" [options]="languageItems" formControlName="videoLanguages" [showToggleAll]="true" | 34 | formControlName="videoLanguages" [availableItems]="languageItems" |
35 | [defaultLabel]="getDefaultVideoLanguageLabel()" [selectedItemsLabel]="getSelectedVideoLanguageLabel()" | 35 | [selectableGroup]="true" [selectableGroupAsModel]="true" |
36 | emptyFilterMessage="No results found" i18n-emptyFilterMessage | 36 | > |
37 | ></p-multiSelect> | 37 | </my-select-checkbox > |
38 | </div> | 38 | </div> |
39 | </div> | 39 | </div> |
40 | 40 | ||
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.scss b/client/src/app/shared/shared-user-settings/user-video-settings.component.scss index 430250b87..d6a17703a 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.scss +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.scss | |||
@@ -19,6 +19,10 @@ input[type=submit] { | |||
19 | margin-bottom: 30px; | 19 | margin-bottom: 30px; |
20 | } | 20 | } |
21 | 21 | ||
22 | my-select-checkbox { | ||
23 | @include ng-select(340px); | ||
24 | } | ||
25 | |||
22 | .form-group-select { | 26 | .form-group-select { |
23 | margin-bottom: 30px; | 27 | margin-bottom: 30px; |
24 | } | 28 | } |
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts index 4e4539936..eb340e24d 100644 --- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts +++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | import { pick } from 'lodash-es' | 1 | import { pick } from 'lodash-es' |
2 | import { SelectItem } from 'primeng/api' | ||
3 | import { forkJoin, Subject, Subscription } from 'rxjs' | 2 | import { forkJoin, Subject, Subscription } from 'rxjs' |
4 | import { first } from 'rxjs/operators' | 3 | import { first } from 'rxjs/operators' |
5 | import { Component, Input, OnDestroy, OnInit } from '@angular/core' | 4 | import { Component, Input, OnDestroy, OnInit } from '@angular/core' |
6 | import { AuthService, Notifier, ServerService, User, UserService } from '@app/core' | 5 | import { AuthService, Notifier, ServerService, User, UserService } from '@app/core' |
7 | import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' | 6 | import { FormReactive, FormValidatorService, ItemSelectCheckboxValue, SelectOptionsItem } from '@app/shared/shared-forms' |
8 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
9 | import { UserUpdateMe } from '@shared/models' | 8 | import { UserUpdateMe } from '@shared/models' |
10 | import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' | 9 | import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' |
@@ -20,10 +19,12 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
20 | @Input() notifyOnUpdate = true | 19 | @Input() notifyOnUpdate = true |
21 | @Input() userInformationLoaded: Subject<any> | 20 | @Input() userInformationLoaded: Subject<any> |
22 | 21 | ||
23 | languageItems: SelectItem[] = [] | 22 | languageItems: SelectOptionsItem[] = [] |
24 | defaultNSFWPolicy: NSFWPolicyType | 23 | defaultNSFWPolicy: NSFWPolicyType |
25 | formValuesWatcher: Subscription | 24 | formValuesWatcher: Subscription |
26 | 25 | ||
26 | private allLanguagesGroup: string | ||
27 | |||
27 | constructor ( | 28 | constructor ( |
28 | protected formValidatorService: FormValidatorService, | 29 | protected formValidatorService: FormValidatorService, |
29 | private authService: AuthService, | 30 | private authService: AuthService, |
@@ -36,6 +37,8 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
36 | } | 37 | } |
37 | 38 | ||
38 | ngOnInit () { | 39 | ngOnInit () { |
40 | this.allLanguagesGroup = this.i18n('All languages') | ||
41 | |||
39 | let oldForm: any | 42 | let oldForm: any |
40 | 43 | ||
41 | this.buildForm({ | 44 | this.buildForm({ |
@@ -51,13 +54,15 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
51 | this.serverService.getConfig(), | 54 | this.serverService.getConfig(), |
52 | this.userInformationLoaded.pipe(first()) | 55 | this.userInformationLoaded.pipe(first()) |
53 | ]).subscribe(([ languages, config ]) => { | 56 | ]).subscribe(([ languages, config ]) => { |
54 | this.languageItems = [ { label: this.i18n('Unknown language'), value: '_unknown' } ] | 57 | const group = this.allLanguagesGroup |
58 | |||
59 | this.languageItems = [ { label: this.i18n('Unknown language'), id: '_unknown', group } ] | ||
55 | this.languageItems = this.languageItems | 60 | this.languageItems = this.languageItems |
56 | .concat(languages.map(l => ({ label: l.label, value: l.id }))) | 61 | .concat(languages.map(l => ({ label: l.label, id: l.id, group }))) |
57 | 62 | ||
58 | const videoLanguages = this.user.videoLanguages | 63 | const videoLanguages: ItemSelectCheckboxValue[] = this.user.videoLanguages |
59 | ? this.user.videoLanguages | 64 | ? this.user.videoLanguages.map(l => ({ id: l })) |
60 | : this.languageItems.map(l => l.value) | 65 | : [ { group } ] |
61 | 66 | ||
62 | this.defaultNSFWPolicy = config.instance.defaultNSFWPolicy | 67 | this.defaultNSFWPolicy = config.instance.defaultNSFWPolicy |
63 | 68 | ||
@@ -71,10 +76,12 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
71 | 76 | ||
72 | if (this.reactiveUpdate) { | 77 | if (this.reactiveUpdate) { |
73 | oldForm = { ...this.form.value } | 78 | oldForm = { ...this.form.value } |
79 | |||
74 | this.formValuesWatcher = this.form.valueChanges.subscribe((formValue: any) => { | 80 | this.formValuesWatcher = this.form.valueChanges.subscribe((formValue: any) => { |
75 | const updatedKey = Object.keys(formValue).find(k => formValue[k] !== oldForm[k]) | 81 | const updatedKey = Object.keys(formValue).find(k => formValue[k] !== oldForm[k]) |
76 | oldForm = { ...this.form.value } | 82 | oldForm = { ...this.form.value } |
77 | this.updateDetails([updatedKey]) | 83 | |
84 | this.updateDetails([ updatedKey ]) | ||
78 | }) | 85 | }) |
79 | } | 86 | } |
80 | }) | 87 | }) |
@@ -91,16 +98,24 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit, | |||
91 | const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] | 98 | const autoPlayNextVideo = this.form.value['autoPlayNextVideo'] |
92 | 99 | ||
93 | let videoLanguages: string[] = this.form.value['videoLanguages'] | 100 | let videoLanguages: string[] = this.form.value['videoLanguages'] |
101 | |||
94 | if (Array.isArray(videoLanguages)) { | 102 | if (Array.isArray(videoLanguages)) { |
95 | if (videoLanguages.length === this.languageItems.length) { | 103 | if (videoLanguages.length > 20) { |
96 | videoLanguages = null // null means "All" | 104 | this.notifier.error(this.i18n('Too many languages are enabled. Please enable them all or stay below 20 enabled languages.')) |
97 | } else if (videoLanguages.length > 20) { | ||
98 | this.notifier.error('Too many languages are enabled. Please enable them all or stay below 20 enabled languages.') | ||
99 | return | 105 | return |
100 | } else if (videoLanguages.length === 0) { | 106 | } |
101 | this.notifier.error('You need to enabled at least 1 video language.') | 107 | |
108 | if (videoLanguages.length === 0) { | ||
109 | this.notifier.error(this.i18n('You need to enable at least 1 video language.')) | ||
102 | return | 110 | return |
103 | } | 111 | } |
112 | |||
113 | if ( | ||
114 | videoLanguages.length === this.languageItems.length || | ||
115 | (videoLanguages.length === 1 && videoLanguages[0] === this.allLanguagesGroup) | ||
116 | ) { | ||
117 | videoLanguages = null // null means "All" | ||
118 | } | ||
104 | } | 119 | } |
105 | 120 | ||
106 | let details: UserUpdateMe = { | 121 | let details: UserUpdateMe = { |