From dd24f1bb0a4b252e5342b251ba36853364da7b8e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 19 Aug 2021 09:24:29 +0200 Subject: Add video filters to common video pages --- .../advanced-input-filter.component.ts | 3 +- client/src/app/shared/shared-forms/select/index.ts | 3 + .../select/select-categories.component.html | 8 ++ .../select/select-categories.component.ts | 71 +++++++++++++ .../select/select-checkbox-all.component.ts | 115 +++++++++++++++++++++ .../select/select-checkbox.component.html | 2 - .../select/select-checkbox.component.ts | 7 +- .../select/select-languages.component.html | 9 ++ .../select/select-languages.component.ts | 74 +++++++++++++ .../app/shared/shared-forms/shared-form.module.ts | 9 ++ 10 files changed, 293 insertions(+), 8 deletions(-) create mode 100644 client/src/app/shared/shared-forms/select/select-categories.component.html create mode 100644 client/src/app/shared/shared-forms/select/select-categories.component.ts create mode 100644 client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts create mode 100644 client/src/app/shared/shared-forms/select/select-languages.component.html create mode 100644 client/src/app/shared/shared-forms/select/select-languages.component.ts (limited to 'client/src/app/shared/shared-forms') diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts index c11f1ad1d..72cd6d460 100644 --- a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts +++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts @@ -18,6 +18,7 @@ const logger = debug('peertube:AdvancedInputFilterComponent') }) export class AdvancedInputFilterComponent implements OnInit, AfterViewInit { @Input() filters: AdvancedInputFilter[] = [] + @Input() emitOnInit = true @Output() search = new EventEmitter() @@ -42,7 +43,7 @@ export class AdvancedInputFilterComponent implements OnInit, AfterViewInit { this.viewInitialized = true // Init after view init to not send an event too early - if (this.emitSearchAfterViewInit) this.emitSearch() + if (this.emitOnInit && this.emitSearchAfterViewInit) this.emitSearch() } onInputSearch (event: Event) { diff --git a/client/src/app/shared/shared-forms/select/index.ts b/client/src/app/shared/shared-forms/select/index.ts index e387e1f48..a3d554ee2 100644 --- a/client/src/app/shared/shared-forms/select/index.ts +++ b/client/src/app/shared/shared-forms/select/index.ts @@ -1,5 +1,8 @@ +export * from './select-categories.component' export * from './select-channel.component' +export * from './select-checkbox-all.component' export * from './select-checkbox.component' export * from './select-custom-value.component' +export * from './select-languages.component' export * from './select-options.component' export * from './select-tags.component' diff --git a/client/src/app/shared/shared-forms/select/select-categories.component.html b/client/src/app/shared/shared-forms/select/select-categories.component.html new file mode 100644 index 000000000..2ec2f1264 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-categories.component.html @@ -0,0 +1,8 @@ + + diff --git a/client/src/app/shared/shared-forms/select/select-categories.component.ts b/client/src/app/shared/shared-forms/select/select-categories.component.ts new file mode 100644 index 000000000..b921714ff --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-categories.component.ts @@ -0,0 +1,71 @@ + +import { Component, forwardRef, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { ServerService } from '@app/core' +import { SelectOptionsItem } from '../../../../types/select-options-item.model' +import { ItemSelectCheckboxValue } from './select-checkbox.component' + +@Component({ + selector: 'my-select-categories', + styleUrls: [ './select-shared.component.scss' ], + templateUrl: './select-categories.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectCategoriesComponent), + multi: true + } + ] +}) +export class SelectCategoriesComponent implements ControlValueAccessor, OnInit { + selectedCategories: ItemSelectCheckboxValue[] = [] + availableCategories: SelectOptionsItem[] = [] + + allCategoriesGroup = $localize`All categories` + + // Fix a bug on ng-select when we update items after we selected items + private toWrite: any + private loaded = false + + constructor ( + private server: ServerService + ) { + + } + + ngOnInit () { + this.server.getVideoCategories() + .subscribe( + categories => { + this.availableCategories = categories.map(c => ({ label: c.label, id: c.id + '', group: this.allCategoriesGroup })) + this.loaded = true + this.writeValue(this.toWrite) + } + ) + } + + propagateChange = (_: any) => { /* empty */ } + + writeValue (categories: string[] | number[]) { + if (!this.loaded) { + this.toWrite = categories + return + } + + this.selectedCategories = categories + ? categories.map(c => c + '') + : categories as string[] + } + + registerOnChange (fn: (_: any) => void) { + this.propagateChange = fn + } + + registerOnTouched () { + // Unused + } + + onModelChange () { + this.propagateChange(this.selectedCategories) + } +} diff --git a/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts b/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts new file mode 100644 index 000000000..ebf7b77a6 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-checkbox-all.component.ts @@ -0,0 +1,115 @@ +import { Component, forwardRef, Input } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { Notifier } from '@app/core' +import { SelectOptionsItem } from '../../../../types/select-options-item.model' +import { ItemSelectCheckboxValue } from './select-checkbox.component' + +@Component({ + selector: 'my-select-checkbox-all', + styleUrls: [ './select-shared.component.scss' ], + + template: ` + + `, + + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectCheckboxAllComponent), + multi: true + } + ] +}) +export class SelectCheckboxAllComponent implements ControlValueAccessor { + @Input() availableItems: SelectOptionsItem[] = [] + @Input() allGroupLabel: string + + @Input() placeholder: string + @Input() maxItems: number + + selectedItems: ItemSelectCheckboxValue[] + + constructor ( + private notifier: Notifier + ) { + + } + + propagateChange = (_: any) => { /* empty */ } + + writeValue (items: string[]) { + this.selectedItems = items + ? items.map(l => ({ id: l })) + : [ { group: this.allGroupLabel } ] + } + + registerOnChange (fn: (_: any) => void) { + this.propagateChange = fn + } + + registerOnTouched () { + // Unused + } + + onModelChange () { + if (!this.isMaxConstraintValid()) return + + this.propagateChange(this.buildOutputItems()) + } + + onBlur () { + // Automatically use "All languages" if the user did not select any language + if (Array.isArray(this.selectedItems) && this.selectedItems.length === 0) { + this.selectedItems = [ { group: this.allGroupLabel } ] + } + } + + private isMaxConstraintValid () { + if (!this.maxItems) return true + + const outputItems = this.buildOutputItems() + if (!outputItems) return true + + if (outputItems.length >= this.maxItems) { + this.notifier.error($localize`You can't select more than ${this.maxItems} items`) + + return false + } + + return true + } + + private buildOutputItems () { + if (!Array.isArray(this.selectedItems)) return undefined + + // null means "All" + if (this.selectedItems.length === 0 || this.selectedItems.length === this.availableItems.length) { + return null + } + + if (this.selectedItems.length === 1) { + const item = this.selectedItems[0] + + const itemGroup = typeof item === 'string' || typeof item === 'number' + ? item + : item.group + + if (itemGroup === this.allGroupLabel) return null + } + + return this.selectedItems.map(l => { + if (typeof l === 'string' || typeof l === 'number') return l + + if (l.group) return l.group + + return l.id + '' + }) + } +} 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 index f5af2932e..7b49a0c01 100644 --- a/client/src/app/shared/shared-forms/select/select-checkbox.component.html +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.html @@ -18,8 +18,6 @@ groupBy="group" [compareWith]="compareFn" - - [maxSelectedItems]="maxSelectedItems" > 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 index c2523f15c..12f697628 100644 --- a/client/src/app/shared/shared-forms/select/select-checkbox.component.ts +++ b/client/src/app/shared/shared-forms/select/select-checkbox.component.ts @@ -2,7 +2,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core' import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' import { SelectOptionsItem } from '../../../../types/select-options-item.model' -export type ItemSelectCheckboxValue = { id?: string | number, group?: string } | string +export type ItemSelectCheckboxValue = { id?: string, group?: string } | string @Component({ selector: 'my-select-checkbox', @@ -21,7 +21,6 @@ export class SelectCheckboxComponent implements OnInit, ControlValueAccessor { @Input() selectedItems: ItemSelectCheckboxValue[] = [] @Input() selectableGroup: boolean @Input() selectableGroupAsModel: boolean - @Input() maxSelectedItems: number @Input() placeholder: string ngOnInit () { @@ -46,8 +45,6 @@ export class SelectCheckboxComponent implements OnInit, ControlValueAccessor { } else { this.selectedItems = items } - - this.propagateChange(this.selectedItems) } registerOnChange (fn: (_: any) => void) { @@ -63,7 +60,7 @@ export class SelectCheckboxComponent implements OnInit, ControlValueAccessor { } compareFn (item: SelectOptionsItem, selected: ItemSelectCheckboxValue) { - if (typeof selected === 'string') { + if (typeof selected === 'string' || typeof selected === 'number') { return item.id === selected } diff --git a/client/src/app/shared/shared-forms/select/select-languages.component.html b/client/src/app/shared/shared-forms/select/select-languages.component.html new file mode 100644 index 000000000..6eba26a56 --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-languages.component.html @@ -0,0 +1,9 @@ + + diff --git a/client/src/app/shared/shared-forms/select/select-languages.component.ts b/client/src/app/shared/shared-forms/select/select-languages.component.ts new file mode 100644 index 000000000..742163ede --- /dev/null +++ b/client/src/app/shared/shared-forms/select/select-languages.component.ts @@ -0,0 +1,74 @@ +import { Component, forwardRef, Input, OnInit } from '@angular/core' +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' +import { ServerService } from '@app/core' +import { SelectOptionsItem } from '../../../../types/select-options-item.model' +import { ItemSelectCheckboxValue } from './select-checkbox.component' + +@Component({ + selector: 'my-select-languages', + styleUrls: [ './select-shared.component.scss' ], + templateUrl: './select-languages.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectLanguagesComponent), + multi: true + } + ] +}) +export class SelectLanguagesComponent implements ControlValueAccessor, OnInit { + @Input() maxLanguages: number + + selectedLanguages: ItemSelectCheckboxValue[] + availableLanguages: SelectOptionsItem[] = [] + + allLanguagesGroup = $localize`All languages` + + // Fix a bug on ng-select when we update items after we selected items + private toWrite: any + private loaded = false + + constructor ( + private server: ServerService + ) { + + } + + ngOnInit () { + this.server.getVideoLanguages() + .subscribe( + languages => { + this.availableLanguages = [ { label: $localize`Unknown language`, id: '_unknown', group: this.allLanguagesGroup } ] + + this.availableLanguages = this.availableLanguages + .concat(languages.map(l => ({ label: l.label, id: l.id, group: this.allLanguagesGroup }))) + + this.loaded = true + this.writeValue(this.toWrite) + } + ) + } + + propagateChange = (_: any) => { /* empty */ } + + writeValue (languages: ItemSelectCheckboxValue[]) { + if (!this.loaded) { + this.toWrite = languages + return + } + + this.selectedLanguages = languages + } + + registerOnChange (fn: (_: any) => void) { + this.propagateChange = fn + } + + registerOnTouched () { + // Unused + } + + onModelChange () { + this.propagateChange(this.selectedLanguages) + } +} 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 5417f7342..60c2f66ae 100644 --- a/client/src/app/shared/shared-forms/shared-form.module.ts +++ b/client/src/app/shared/shared-forms/shared-form.module.ts @@ -15,9 +15,12 @@ import { PeertubeCheckboxComponent } from './peertube-checkbox.component' import { PreviewUploadComponent } from './preview-upload.component' import { ReactiveFileComponent } from './reactive-file.component' import { + SelectCategoriesComponent, SelectChannelComponent, + SelectCheckboxAllComponent, SelectCheckboxComponent, SelectCustomValueComponent, + SelectLanguagesComponent, SelectOptionsComponent, SelectTagsComponent } from './select' @@ -52,6 +55,9 @@ import { TimestampInputComponent } from './timestamp-input.component' SelectTagsComponent, SelectCheckboxComponent, SelectCustomValueComponent, + SelectLanguagesComponent, + SelectCategoriesComponent, + SelectCheckboxAllComponent, DynamicFormFieldComponent, @@ -80,6 +86,9 @@ import { TimestampInputComponent } from './timestamp-input.component' SelectTagsComponent, SelectCheckboxComponent, SelectCustomValueComponent, + SelectLanguagesComponent, + SelectCategoriesComponent, + SelectCheckboxAllComponent, DynamicFormFieldComponent, -- cgit v1.2.3