9 import { Router, Params, ActivatedRoute } from '@angular/router'
10 import { AuthService, ServerService } from '@app/core'
11 import { first, tap } from 'rxjs/operators'
12 import { ListKeyManager } from '@angular/cdk/a11y'
13 import { UP_ARROW, DOWN_ARROW, ENTER } from '@angular/cdk/keycodes'
14 import { SuggestionComponent, Result } from './suggestion.component'
15 import { of } from 'rxjs'
16 import { ServerConfig } from '@shared/models'
19 selector: 'my-search-typeahead',
20 templateUrl: './search-typeahead.component.html',
21 styleUrls: [ './search-typeahead.component.scss' ]
23 export class SearchTypeaheadComponent implements OnInit, OnDestroy {
24 @ViewChild('searchVideo', { static: true }) searchInput: ElementRef<HTMLInputElement>
31 serverConfig: ServerConfig
33 inThisChannelText: string
35 keyboardEventsManager: ListKeyManager<SuggestionComponent>
36 results: Result[] = []
39 private authService: AuthService,
40 private router: Router,
41 private route: ActivatedRoute,
42 private serverService: ServerService
46 const query = this.route.snapshot.queryParams
47 if (query['search']) this.search = query['search']
49 this.serverService.getConfig()
50 .subscribe(config => this.serverConfig = config)
54 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
58 return this.keyboardEventsManager?.activeItem?.result
61 get areInstructionsDisplayed () {
66 return this.search && this.newSearch && this.activeResult?.type === 'search-global'
69 get canSearchAnyURI () {
70 if (!this.serverConfig) return false
71 return this.authService.isLoggedIn()
72 ? this.serverConfig.search.remoteUri.users
73 : this.serverConfig.search.remoteUri.anonymous
82 let results: Result[] = []
86 /* Channel search is still unimplemented. Uncomment when it is.
89 type: 'search-channel'
94 type: 'search-instance',
97 /* Global search is still unimplemented. Uncomment when it is.
100 type: 'search-global'
107 this.results = results.filter(
108 (result: Result) => {
109 // if we're not in a channel or one of its videos/playlits, show all channel-related results
110 if (!(this.hasChannel || this.inChannel)) return !result.type.includes('channel')
111 // if we're in a channel, show all channel-related results except for the channel redirection itself
112 if (this.inChannel) return result.type !== 'channel'
113 // all other result types are kept
119 setEventItems (event: { items: QueryList<SuggestionComponent>, index?: number }) {
120 event.items.forEach(e => {
121 if (this.keyboardEventsManager.activeItem && this.keyboardEventsManager.activeItem === e) {
122 this.keyboardEventsManager.activeItem.active = true
129 initKeyboardEventsManager (event: { items: QueryList<SuggestionComponent>, index?: number }) {
130 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
132 this.keyboardEventsManager = new ListKeyManager(event.items)
134 if (event.index !== undefined) {
135 this.keyboardEventsManager.setActiveItem(event.index)
137 this.keyboardEventsManager.setFirstItemActive()
140 this.keyboardEventsManager.change.subscribe(
141 _ => this.setEventItems(event)
145 handleKeyUp (event: KeyboardEvent) {
146 event.stopImmediatePropagation()
147 if (!this.keyboardEventsManager) return
152 this.keyboardEventsManager.onKeydown(event)
155 this.newSearch = false
162 const queryParams: Params = {}
164 if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
165 Object.assign(queryParams, this.route.snapshot.queryParams)
168 Object.assign(queryParams, { search: this.search })
170 const o = this.authService.isLoggedIn()
171 ? this.loadUserLanguagesIfNeeded(queryParams)
174 o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
177 private loadUserLanguagesIfNeeded (queryParams: any) {
178 if (queryParams && queryParams.languageOneOf) return of(queryParams)
180 return this.authService.userInformationLoaded
183 tap(() => Object.assign(queryParams, { languageOneOf: this.authService.getUser().videoLanguages }))