diff options
author | Chocobozzz <me@florianbigard.com> | 2021-02-09 16:35:48 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-02-10 11:36:40 +0100 |
commit | ead64cdf8d917fa0d6a20271e42378f38e5f2407 (patch) | |
tree | 681e9dba853107edab45d8185688dadde4850efb /client/src/app/shared | |
parent | b9c9fefe820fb0b3aaa3c2b5af73bafb29d890d0 (diff) | |
download | PeerTube-ead64cdf8d917fa0d6a20271e42378f38e5f2407.tar.gz PeerTube-ead64cdf8d917fa0d6a20271e42378f38e5f2407.tar.zst PeerTube-ead64cdf8d917fa0d6a20271e42378f38e5f2407.zip |
Support custom value in ng-select
Diffstat (limited to 'client/src/app/shared')
10 files changed, 119 insertions, 61 deletions
diff --git a/client/src/app/shared/shared-forms/select/index.ts b/client/src/app/shared/shared-forms/select/index.ts index 33459b23b..e387e1f48 100644 --- a/client/src/app/shared/shared-forms/select/index.ts +++ b/client/src/app/shared/shared-forms/select/index.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | export * from './select-channel.component' | 1 | export * from './select-channel.component' |
2 | export * from './select-checkbox.component' | ||
3 | export * from './select-custom-value.component' | ||
2 | export * from './select-options.component' | 4 | export * from './select-options.component' |
3 | export * from './select-tags.component' | 5 | export * from './select-tags.component' |
4 | export * from './select-checkbox.component' | ||
diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.html b/client/src/app/shared/shared-forms/select/select-custom-input.component.html deleted file mode 100644 index 84fa15c3d..000000000 --- a/client/src/app/shared/shared-forms/select/select-custom-input.component.html +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | <ng-select | ||
2 | [(ngModel)]="selectedId" | ||
3 | (ngModelChange)="onModelChange()" | ||
4 | [bindLabel]="bindLabel" | ||
5 | [bindValue]="bindValue" | ||
6 | [clearable]="clearable" | ||
7 | [searchable]="searchable" | ||
8 | > | ||
9 | <ng-option *ngFor="let item of items" [value]="item.id"> | ||
10 | {{ channel.label }} | ||
11 | </ng-option> | ||
12 | |||
13 | <ng-content></ng-content> | ||
14 | </ng-select> | ||
diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.scss b/client/src/app/shared/shared-forms/select/select-custom-input.component.scss deleted file mode 100644 index e69de29bb..000000000 --- a/client/src/app/shared/shared-forms/select/select-custom-input.component.scss +++ /dev/null | |||
diff --git a/client/src/app/shared/shared-forms/select/select-custom-input.component.ts b/client/src/app/shared/shared-forms/select/select-custom-input.component.ts deleted file mode 100644 index ba6fef8ad..000000000 --- a/client/src/app/shared/shared-forms/select/select-custom-input.component.ts +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | import { Component, forwardRef, Input } from '@angular/core' | ||
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | ||
3 | |||
4 | @Component({ | ||
5 | selector: 'my-select-custom-input', | ||
6 | styleUrls: [ './select-custom-input.component.scss' ], | ||
7 | templateUrl: './select-custom-input.component.html', | ||
8 | providers: [ | ||
9 | { | ||
10 | provide: NG_VALUE_ACCESSOR, | ||
11 | useExisting: forwardRef(() => SelectCustomInputComponent), | ||
12 | multi: true | ||
13 | } | ||
14 | ] | ||
15 | }) | ||
16 | export class SelectCustomInputComponent implements ControlValueAccessor { | ||
17 | @Input() items: any[] = [] | ||
18 | |||
19 | selectedId: number | ||
20 | |||
21 | // ng-select options | ||
22 | bindLabel = 'label' | ||
23 | bindValue = 'id' | ||
24 | clearable = false | ||
25 | searchable = false | ||
26 | |||
27 | propagateChange = (_: any) => { /* empty */ } | ||
28 | |||
29 | writeValue (id: number) { | ||
30 | this.selectedId = id | ||
31 | } | ||
32 | |||
33 | registerOnChange (fn: (_: any) => void) { | ||
34 | this.propagateChange = fn | ||
35 | } | ||
36 | |||
37 | registerOnTouched () { | ||
38 | // Unused | ||
39 | } | ||
40 | |||
41 | onModelChange () { | ||
42 | this.propagateChange(this.selectedId) | ||
43 | } | ||
44 | } | ||
diff --git a/client/src/app/shared/shared-forms/select/select-custom-value.component.html b/client/src/app/shared/shared-forms/select/select-custom-value.component.html new file mode 100644 index 000000000..5fdf432ff --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.html | |||
@@ -0,0 +1,14 @@ | |||
1 | <div class="root"> | ||
2 | <my-select-options | ||
3 | [items]="itemsWithCustom" | ||
4 | [clearable]="clearable" | ||
5 | [searchable]="searchable" | ||
6 | [groupBy]="groupBy" | ||
7 | [labelForId]="labelForId" | ||
8 | |||
9 | [(ngModel)]="selectedId" | ||
10 | (ngModelChange)="onModelChange()" | ||
11 | ></my-select-options> | ||
12 | |||
13 | <input *ngIf="isCustomValue()" [(ngModel)]="customValue" (ngModelChange)="onModelChange()" type="text" class="form-control" /> | ||
14 | </div> | ||
diff --git a/client/src/app/shared/shared-forms/select/select-custom-value.component.ts b/client/src/app/shared/shared-forms/select/select-custom-value.component.ts new file mode 100644 index 000000000..a8e5ad0d3 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-custom-value.component.ts | |||
@@ -0,0 +1,76 @@ | |||
1 | import { Component, forwardRef, Input, OnChanges } from '@angular/core' | ||
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | ||
3 | import { SelectOptionsItem } from './select-options.component' | ||
4 | |||
5 | @Component({ | ||
6 | selector: 'my-select-custom-value', | ||
7 | styleUrls: [ './select-shared.component.scss' ], | ||
8 | templateUrl: './select-custom-value.component.html', | ||
9 | providers: [ | ||
10 | { | ||
11 | provide: NG_VALUE_ACCESSOR, | ||
12 | useExisting: forwardRef(() => SelectCustomValueComponent), | ||
13 | multi: true | ||
14 | } | ||
15 | ] | ||
16 | }) | ||
17 | export class SelectCustomValueComponent implements ControlValueAccessor, OnChanges { | ||
18 | @Input() items: SelectOptionsItem[] = [] | ||
19 | @Input() clearable = false | ||
20 | @Input() searchable = false | ||
21 | @Input() groupBy: string | ||
22 | @Input() labelForId: string | ||
23 | |||
24 | customValue: number | string = '' | ||
25 | selectedId: number | string | ||
26 | |||
27 | itemsWithCustom: SelectOptionsItem[] = [] | ||
28 | |||
29 | ngOnChanges () { | ||
30 | this.itemsWithCustom = this.getItems() | ||
31 | } | ||
32 | |||
33 | propagateChange = (_: any) => { /* empty */ } | ||
34 | |||
35 | writeValue (id: number | string) { | ||
36 | this.selectedId = id | ||
37 | |||
38 | if (this.isSelectedIdInItems() !== true) { | ||
39 | this.selectedId = 'other' | ||
40 | this.customValue = id | ||
41 | } | ||
42 | } | ||
43 | |||
44 | registerOnChange (fn: (_: any) => void) { | ||
45 | this.propagateChange = fn | ||
46 | } | ||
47 | |||
48 | registerOnTouched () { | ||
49 | // Unused | ||
50 | } | ||
51 | |||
52 | onModelChange () { | ||
53 | if (this.selectedId === 'other') { | ||
54 | return this.propagateChange(this.customValue) | ||
55 | } | ||
56 | |||
57 | return this.propagateChange(this.selectedId) | ||
58 | } | ||
59 | |||
60 | isSelectedIdInItems () { | ||
61 | return !!this.items.find(i => i.id === this.selectedId) | ||
62 | } | ||
63 | |||
64 | getItems () { | ||
65 | const other: SelectOptionsItem = { | ||
66 | id: 'other', | ||
67 | label: $localize`Custom value...` | ||
68 | } | ||
69 | |||
70 | return this.items.concat([ other ]) | ||
71 | } | ||
72 | |||
73 | isCustomValue () { | ||
74 | return this.selectedId === 'other' | ||
75 | } | ||
76 | } | ||
diff --git a/client/src/app/shared/shared-forms/select/select-options.component.html b/client/src/app/shared/shared-forms/select/select-options.component.html index 6d0d7e925..3b1761255 100644 --- a/client/src/app/shared/shared-forms/select/select-options.component.html +++ b/client/src/app/shared/shared-forms/select/select-options.component.html | |||
@@ -6,6 +6,7 @@ | |||
6 | [clearable]="clearable" | 6 | [clearable]="clearable" |
7 | [labelForId]="labelForId" | 7 | [labelForId]="labelForId" |
8 | [searchable]="searchable" | 8 | [searchable]="searchable" |
9 | [searchFn]="searchFn" | ||
9 | 10 | ||
10 | bindLabel="label" | 11 | bindLabel="label" |
11 | bindValue="id" | 12 | bindValue="id" |
diff --git a/client/src/app/shared/shared-forms/select/select-options.component.ts b/client/src/app/shared/shared-forms/select/select-options.component.ts index f0abd1a68..51a3f515d 100644 --- a/client/src/app/shared/shared-forms/select/select-options.component.ts +++ b/client/src/app/shared/shared-forms/select/select-options.component.ts | |||
@@ -27,6 +27,7 @@ export class SelectOptionsComponent implements ControlValueAccessor { | |||
27 | @Input() searchable = false | 27 | @Input() searchable = false |
28 | @Input() groupBy: string | 28 | @Input() groupBy: string |
29 | @Input() labelForId: string | 29 | @Input() labelForId: string |
30 | @Input() searchFn: any | ||
30 | 31 | ||
31 | selectedId: number | string | 32 | selectedId: number | string |
32 | 33 | ||
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 index 0b4c6b784..1a4192b55 100644 --- a/client/src/app/shared/shared-forms/select/select-shared.component.scss +++ b/client/src/app/shared/shared-forms/select/select-shared.component.scss | |||
@@ -30,3 +30,18 @@ ng-select ::ng-deep { | |||
30 | width: 20px; | 30 | width: 20px; |
31 | } | 31 | } |
32 | } | 32 | } |
33 | |||
34 | .root { | ||
35 | display:flex; | ||
36 | |||
37 | > my-select-options { | ||
38 | flex-grow: 1; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | input[type=text] { | ||
43 | margin-left: 5px; | ||
44 | |||
45 | @include peertube-input-text($form-base-input-width); | ||
46 | display: block; | ||
47 | } | ||
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 22e8dd05a..9bdd138a1 100644 --- a/client/src/app/shared/shared-forms/shared-form.module.ts +++ b/client/src/app/shared/shared-forms/shared-form.module.ts | |||
@@ -7,13 +7,19 @@ import { SharedGlobalIconModule } from '../shared-icons' | |||
7 | import { SharedMainModule } from '../shared-main/shared-main.module' | 7 | import { SharedMainModule } from '../shared-main/shared-main.module' |
8 | import { DynamicFormFieldComponent } from './dynamic-form-field.component' | 8 | import { DynamicFormFieldComponent } from './dynamic-form-field.component' |
9 | import { FormValidatorService } from './form-validator.service' | 9 | import { FormValidatorService } from './form-validator.service' |
10 | import { InputToggleHiddenComponent } from './input-toggle-hidden.component' | ||
11 | import { InputSwitchComponent } from './input-switch.component' | 10 | import { InputSwitchComponent } from './input-switch.component' |
11 | import { InputToggleHiddenComponent } from './input-toggle-hidden.component' | ||
12 | import { MarkdownTextareaComponent } from './markdown-textarea.component' | 12 | import { MarkdownTextareaComponent } from './markdown-textarea.component' |
13 | import { PeertubeCheckboxComponent } from './peertube-checkbox.component' | 13 | import { PeertubeCheckboxComponent } from './peertube-checkbox.component' |
14 | import { PreviewUploadComponent } from './preview-upload.component' | 14 | import { PreviewUploadComponent } from './preview-upload.component' |
15 | import { ReactiveFileComponent } from './reactive-file.component' | 15 | import { ReactiveFileComponent } from './reactive-file.component' |
16 | import { SelectChannelComponent, SelectCheckboxComponent, SelectOptionsComponent, SelectTagsComponent } from './select' | 16 | import { |
17 | SelectChannelComponent, | ||
18 | SelectCheckboxComponent, | ||
19 | SelectCustomValueComponent, | ||
20 | SelectOptionsComponent, | ||
21 | SelectTagsComponent | ||
22 | } from './select' | ||
17 | import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' | 23 | import { TextareaAutoResizeDirective } from './textarea-autoresize.directive' |
18 | import { TimestampInputComponent } from './timestamp-input.component' | 24 | import { TimestampInputComponent } from './timestamp-input.component' |
19 | 25 | ||
@@ -44,6 +50,7 @@ import { TimestampInputComponent } from './timestamp-input.component' | |||
44 | SelectOptionsComponent, | 50 | SelectOptionsComponent, |
45 | SelectTagsComponent, | 51 | SelectTagsComponent, |
46 | SelectCheckboxComponent, | 52 | SelectCheckboxComponent, |
53 | SelectCustomValueComponent, | ||
47 | 54 | ||
48 | DynamicFormFieldComponent | 55 | DynamicFormFieldComponent |
49 | ], | 56 | ], |
@@ -69,6 +76,7 @@ import { TimestampInputComponent } from './timestamp-input.component' | |||
69 | SelectOptionsComponent, | 76 | SelectOptionsComponent, |
70 | SelectTagsComponent, | 77 | SelectTagsComponent, |
71 | SelectCheckboxComponent, | 78 | SelectCheckboxComponent, |
79 | SelectCustomValueComponent, | ||
72 | 80 | ||
73 | DynamicFormFieldComponent | 81 | DynamicFormFieldComponent |
74 | ], | 82 | ], |