]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/header/search-typeahead.component.ts
Creating a user with an empty password will send an email to let him set his password...
[github/Chocobozzz/PeerTube.git] / client / src / app / header / search-typeahead.component.ts
CommitLineData
6af662a5
RK
1import {
2 Component,
6af662a5
RK
3 OnInit,
4 OnDestroy,
9b8a7aa8
RK
5 QueryList,
6 ViewChild,
7 ElementRef
6af662a5 8} from '@angular/core'
9b8a7aa8 9import { Router, Params, ActivatedRoute } from '@angular/router'
9677fca7 10import { AuthService, ServerService } from '@app/core'
9b8a7aa8 11import { first, tap } from 'rxjs/operators'
6af662a5 12import { ListKeyManager } from '@angular/cdk/a11y'
9677fca7 13import { UP_ARROW, DOWN_ARROW, ENTER } from '@angular/cdk/keycodes'
52cc0d54
RK
14import { SuggestionComponent, Result } from './suggestion.component'
15import { of } from 'rxjs'
9677fca7 16import { ServerConfig } from '@shared/models'
f409f0c3
RK
17
18@Component({
19 selector: 'my-search-typeahead',
20 templateUrl: './search-typeahead.component.html',
21 styleUrls: [ './search-typeahead.component.scss' ]
22})
8a979d73 23export class SearchTypeaheadComponent implements OnInit, OnDestroy {
9b8a7aa8 24 @ViewChild('searchVideo', { static: true }) searchInput: ElementRef<HTMLInputElement>
f409f0c3
RK
25
26 hasChannel = false
27 inChannel = false
6af662a5 28 newSearch = true
f409f0c3 29
9b8a7aa8 30 search = ''
9677fca7 31 serverConfig: ServerConfig
f409f0c3 32
f409f0c3
RK
33 inThisChannelText: string
34
6af662a5 35 keyboardEventsManager: ListKeyManager<SuggestionComponent>
8a979d73 36 results: Result[] = []
f409f0c3
RK
37
38 constructor (
39 private authService: AuthService,
40 private router: Router,
52cc0d54 41 private route: ActivatedRoute,
9b8a7aa8
RK
42 private serverService: ServerService
43 ) {}
f409f0c3
RK
44
45 ngOnInit () {
8a979d73
RK
46 const query = this.route.snapshot.queryParams
47 if (query['search']) this.search = query['search']
48
9677fca7
RK
49 this.serverService.getConfig()
50 .subscribe(config => this.serverConfig = config)
f409f0c3
RK
51 }
52
6af662a5
RK
53 ngOnDestroy () {
54 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
55 }
56
6af662a5 57 get activeResult () {
8a979d73 58 return this.keyboardEventsManager?.activeItem?.result
6af662a5
RK
59 }
60
8a979d73 61 get areInstructionsDisplayed () {
9b8a7aa8
RK
62 return !this.search
63 }
64
6af662a5 65 get showHelp () {
8a979d73 66 return this.search && this.newSearch && this.activeResult?.type === 'search-global'
6af662a5
RK
67 }
68
8a979d73 69 get canSearchAnyURI () {
9b8a7aa8
RK
70 if (!this.serverConfig) return false
71 return this.authService.isLoggedIn()
72 ? this.serverConfig.search.remoteUri.users
73 : this.serverConfig.search.remoteUri.anonymous
74 }
75
76 onSearchChange () {
77 this.computeResults()
9677fca7
RK
78 }
79
f409f0c3 80 computeResults () {
6af662a5 81 this.newSearch = true
52cc0d54 82 let results: Result[] = []
f409f0c3 83
9b8a7aa8 84 if (this.search) {
f409f0c3 85 results = [
52cc0d54 86 /* Channel search is still unimplemented. Uncomment when it is.
f409f0c3 87 {
9b8a7aa8 88 text: this.search,
f409f0c3
RK
89 type: 'search-channel'
90 },
52cc0d54 91 */
6af662a5 92 {
9b8a7aa8 93 text: this.search,
52cc0d54
RK
94 type: 'search-instance',
95 default: true
6af662a5 96 },
52cc0d54 97 /* Global search is still unimplemented. Uncomment when it is.
f409f0c3 98 {
9b8a7aa8 99 text: this.search,
f409f0c3
RK
100 type: 'search-global'
101 },
52cc0d54 102 */
f409f0c3
RK
103 ...results
104 ]
105 }
106
107 this.results = results.filter(
52cc0d54 108 (result: Result) => {
f409f0c3
RK
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
9b8a7aa8
RK
112 if (this.inChannel) return result.type !== 'channel'
113 // all other result types are kept
f409f0c3
RK
114 return true
115 }
116 )
117 }
118
52cc0d54
RK
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
123 } else {
124 e.active = false
125 }
126 })
127 }
128
6af662a5
RK
129 initKeyboardEventsManager (event: { items: QueryList<SuggestionComponent>, index?: number }) {
130 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
8a979d73 131
6af662a5 132 this.keyboardEventsManager = new ListKeyManager(event.items)
8a979d73 133
6af662a5
RK
134 if (event.index !== undefined) {
135 this.keyboardEventsManager.setActiveItem(event.index)
52cc0d54
RK
136 } else {
137 this.keyboardEventsManager.setFirstItemActive()
6af662a5 138 }
8a979d73 139
6af662a5 140 this.keyboardEventsManager.change.subscribe(
52cc0d54 141 _ => this.setEventItems(event)
6af662a5
RK
142 )
143 }
144
8a979d73 145 handleKeyUp (event: KeyboardEvent) {
f409f0c3 146 event.stopImmediatePropagation()
8a979d73
RK
147 if (!this.keyboardEventsManager) return
148
149 switch (event.key) {
150 case "ArrowDown":
151 case "ArrowUp":
f409f0c3 152 this.keyboardEventsManager.onKeydown(event)
8a979d73
RK
153 break
154 case "Enter":
6af662a5 155 this.newSearch = false
52cc0d54 156 this.doSearch()
8a979d73 157 break
f409f0c3
RK
158 }
159 }
52cc0d54
RK
160
161 doSearch () {
162 const queryParams: Params = {}
163
164 if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
165 Object.assign(queryParams, this.route.snapshot.queryParams)
166 }
167
9b8a7aa8 168 Object.assign(queryParams, { search: this.search })
52cc0d54
RK
169
170 const o = this.authService.isLoggedIn()
171 ? this.loadUserLanguagesIfNeeded(queryParams)
172 : of(true)
173
174 o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
175 }
176
177 private loadUserLanguagesIfNeeded (queryParams: any) {
178 if (queryParams && queryParams.languageOneOf) return of(queryParams)
179
180 return this.authService.userInformationLoaded
181 .pipe(
182 first(),
183 tap(() => Object.assign(queryParams, { languageOneOf: this.authService.getUser().videoLanguages }))
184 )
185 }
f409f0c3 186}