1 import { Component, ElementRef, OnDestroy, OnInit, QueryList, ViewChild } from '@angular/core'
2 import { ActivatedRoute, Params, Router } from '@angular/router'
3 import { AuthService, ServerService } from '@app/core'
4 import { first, tap } from 'rxjs/operators'
5 import { ListKeyManager } from '@angular/cdk/a11y'
6 import { Result, SuggestionComponent } from './suggestion.component'
7 import { of } from 'rxjs'
8 import { ServerConfig } from '@shared/models'
11 selector: 'my-search-typeahead',
12 templateUrl: './search-typeahead.component.html',
13 styleUrls: [ './search-typeahead.component.scss' ]
15 export class SearchTypeaheadComponent implements OnInit, OnDestroy {
16 @ViewChild('searchVideo', { static: true }) searchInput: ElementRef<HTMLInputElement>
23 serverConfig: ServerConfig
25 inThisChannelText: string
27 keyboardEventsManager: ListKeyManager<SuggestionComponent>
28 results: Result[] = []
31 private authService: AuthService,
32 private router: Router,
33 private route: ActivatedRoute,
34 private serverService: ServerService
38 this.route.queryParams
39 .pipe(first(params => params.search !== undefined && params.search !== null))
40 .subscribe(params => this.search = params.search)
41 this.serverService.getConfig()
42 .subscribe(config => this.serverConfig = config)
46 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
50 return this.keyboardEventsManager?.activeItem?.result
53 get areInstructionsDisplayed () {
58 return this.search && this.newSearch && this.activeResult?.type === 'search-global'
61 get canSearchAnyURI () {
62 if (!this.serverConfig) return false
63 return this.authService.isLoggedIn()
64 ? this.serverConfig.search.remoteUri.users
65 : this.serverConfig.search.remoteUri.anonymous
74 let results: Result[] = []
78 /* Channel search is still unimplemented. Uncomment when it is.
81 type: 'search-channel'
86 type: 'search-instance',
89 /* Global search is still unimplemented. Uncomment when it is.
99 this.results = results.filter(
100 (result: Result) => {
101 // if we're not in a channel or one of its videos/playlits, show all channel-related results
102 if (!(this.hasChannel || this.inChannel)) return !result.type.includes('channel')
103 // if we're in a channel, show all channel-related results except for the channel redirection itself
104 if (this.inChannel) return result.type !== 'channel'
105 // all other result types are kept
111 setEventItems (event: { items: QueryList<SuggestionComponent>, index?: number }) {
112 event.items.forEach(e => {
113 if (this.keyboardEventsManager.activeItem && this.keyboardEventsManager.activeItem === e) {
114 this.keyboardEventsManager.activeItem.active = true
121 initKeyboardEventsManager (event: { items: QueryList<SuggestionComponent>, index?: number }) {
122 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
124 this.keyboardEventsManager = new ListKeyManager(event.items)
126 if (event.index !== undefined) {
127 this.keyboardEventsManager.setActiveItem(event.index)
129 this.keyboardEventsManager.setFirstItemActive()
132 this.keyboardEventsManager.change.subscribe(
133 _ => this.setEventItems(event)
137 handleKeyUp (event: KeyboardEvent) {
138 event.stopImmediatePropagation()
139 if (!this.keyboardEventsManager) return
144 this.keyboardEventsManager.onKeydown(event)
147 this.newSearch = false
154 const queryParams: Params = {}
156 if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
157 Object.assign(queryParams, this.route.snapshot.queryParams)
160 Object.assign(queryParams, { search: this.search })
162 const o = this.authService.isLoggedIn()
163 ? this.loadUserLanguagesIfNeeded(queryParams)
166 o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
169 private loadUserLanguagesIfNeeded (queryParams: any) {
170 if (queryParams && queryParams.languageOneOf) return of(queryParams)
172 return this.authService.userInformationLoaded
175 tap(() => Object.assign(queryParams, { languageOneOf: this.authService.getUser().videoLanguages }))