aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/header/search-typeahead.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/header/search-typeahead.component.ts')
-rw-r--r--client/src/app/header/search-typeahead.component.ts86
1 files changed, 63 insertions, 23 deletions
diff --git a/client/src/app/header/search-typeahead.component.ts b/client/src/app/header/search-typeahead.component.ts
index 084bdd58b..514c04704 100644
--- a/client/src/app/header/search-typeahead.component.ts
+++ b/client/src/app/header/search-typeahead.component.ts
@@ -7,13 +7,15 @@ import {
7 OnDestroy, 7 OnDestroy,
8 QueryList 8 QueryList
9} from '@angular/core' 9} from '@angular/core'
10import { Router, NavigationEnd } from '@angular/router' 10import { Router, NavigationEnd, Params, ActivatedRoute } from '@angular/router'
11import { AuthService } from '@app/core' 11import { AuthService } from '@app/core'
12import { I18n } from '@ngx-translate/i18n-polyfill' 12import { I18n } from '@ngx-translate/i18n-polyfill'
13import { filter } from 'rxjs/operators' 13import { filter, first, tap, map } from 'rxjs/operators'
14import { ListKeyManager } from '@angular/cdk/a11y' 14import { ListKeyManager } from '@angular/cdk/a11y'
15import { UP_ARROW, DOWN_ARROW, ENTER, TAB } from '@angular/cdk/keycodes' 15import { UP_ARROW, DOWN_ARROW, ENTER, TAB } from '@angular/cdk/keycodes'
16import { SuggestionComponent } from './suggestion.component' 16import { SuggestionComponent, Result } from './suggestion.component'
17import { of } from 'rxjs'
18import { getParameterByName } from '@app/shared/misc/utils'
17 19
18@Component({ 20@Component({
19 selector: 'my-search-typeahead', 21 selector: 'my-search-typeahead',
@@ -41,6 +43,7 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
41 constructor ( 43 constructor (
42 private authService: AuthService, 44 private authService: AuthService,
43 private router: Router, 45 private router: Router,
46 private route: ActivatedRoute,
44 private i18n: I18n 47 private i18n: I18n
45 ) { 48 ) {
46 this.URIPolicyText = this.i18n('Determines whether you can resolve any distant content, or if your instance only allows doing so for instances it follows.') 49 this.URIPolicyText = this.i18n('Determines whether you can resolve any distant content, or if your instance only allows doing so for instances it follows.')
@@ -50,12 +53,19 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
50 53
51 ngOnInit () { 54 ngOnInit () {
52 this.router.events 55 this.router.events
53 .pipe(filter(event => event instanceof NavigationEnd)) 56 .pipe(filter(e => e instanceof NavigationEnd))
54 .subscribe((event: NavigationEnd) => { 57 .subscribe((event: NavigationEnd) => {
55 this.hasChannel = event.url.startsWith('/videos/watch') 58 this.hasChannel = event.url.startsWith('/videos/watch')
56 this.inChannel = event.url.startsWith('/video-channels') 59 this.inChannel = event.url.startsWith('/video-channels')
57 this.computeResults() 60 this.computeResults()
58 }) 61 })
62
63 this.router.events
64 .pipe(
65 filter(e => e instanceof NavigationEnd),
66 map(() => getParameterByName('search', window.location.href))
67 )
68 .subscribe(searchQuery => this.searchInput.value = searchQuery || '')
59 } 69 }
60 70
61 ngOnDestroy () { 71 ngOnDestroy () {
@@ -82,33 +92,33 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
82 92
83 computeResults () { 93 computeResults () {
84 this.newSearch = true 94 this.newSearch = true
85 let results = [ 95 let results: Result[] = []
86 {
87 text: 'MaƮtre poney',
88 type: 'channel'
89 }
90 ]
91 96
92 if (this.hasSearch) { 97 if (this.hasSearch) {
93 results = [ 98 results = [
99 /* Channel search is still unimplemented. Uncomment when it is.
94 { 100 {
95 text: this.searchInput.value, 101 text: this.searchInput.value,
96 type: 'search-channel' 102 type: 'search-channel'
97 }, 103 },
104 */
98 { 105 {
99 text: this.searchInput.value, 106 text: this.searchInput.value,
100 type: 'search-instance' 107 type: 'search-instance',
108 default: true
101 }, 109 },
110 /* Global search is still unimplemented. Uncomment when it is.
102 { 111 {
103 text: this.searchInput.value, 112 text: this.searchInput.value,
104 type: 'search-global' 113 type: 'search-global'
105 }, 114 },
115 */
106 ...results 116 ...results
107 ] 117 ]
108 } 118 }
109 119
110 this.results = results.filter( 120 this.results = results.filter(
111 result => { 121 (result: Result) => {
112 // if we're not in a channel or one of its videos/playlits, show all channel-related results 122 // if we're not in a channel or one of its videos/playlits, show all channel-related results
113 if (!(this.hasChannel || this.inChannel)) return !result.type.includes('channel') 123 if (!(this.hasChannel || this.inChannel)) return !result.type.includes('channel')
114 // if we're in a channel, show all channel-related results except for the channel redirection itself 124 // if we're in a channel, show all channel-related results except for the channel redirection itself
@@ -118,19 +128,26 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
118 ) 128 )
119 } 129 }
120 130
131 setEventItems (event: { items: QueryList<SuggestionComponent>, index?: number }) {
132 event.items.forEach(e => {
133 if (this.keyboardEventsManager.activeItem && this.keyboardEventsManager.activeItem === e) {
134 this.keyboardEventsManager.activeItem.active = true
135 } else {
136 e.active = false
137 }
138 })
139 }
140
121 initKeyboardEventsManager (event: { items: QueryList<SuggestionComponent>, index?: number }) { 141 initKeyboardEventsManager (event: { items: QueryList<SuggestionComponent>, index?: number }) {
122 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe() 142 if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
123 this.keyboardEventsManager = new ListKeyManager(event.items) 143 this.keyboardEventsManager = new ListKeyManager(event.items)
124 if (event.index !== undefined) { 144 if (event.index !== undefined) {
125 this.keyboardEventsManager.setActiveItem(event.index) 145 this.keyboardEventsManager.setActiveItem(event.index)
126 event.items.forEach(e => e.active = false) 146 } else {
127 this.keyboardEventsManager.activeItem.active = true 147 this.keyboardEventsManager.setFirstItemActive()
128 } 148 }
129 this.keyboardEventsManager.change.subscribe( 149 this.keyboardEventsManager.change.subscribe(
130 val => { 150 _ => this.setEventItems(event)
131 event.items.forEach(e => e.active = false)
132 this.keyboardEventsManager.activeItem.active = true
133 }
134 ) 151 )
135 } 152 }
136 153
@@ -141,17 +158,40 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
141 handleKeyUp (event: KeyboardEvent, indexSelected?: number) { 158 handleKeyUp (event: KeyboardEvent, indexSelected?: number) {
142 event.stopImmediatePropagation() 159 event.stopImmediatePropagation()
143 if (this.keyboardEventsManager) { 160 if (this.keyboardEventsManager) {
144 if (event.keyCode === TAB) { 161 if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
145 this.keyboardEventsManager.setNextItemActive()
146 return false
147 } else if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
148 this.keyboardEventsManager.onKeydown(event) 162 this.keyboardEventsManager.onKeydown(event)
149 return false 163 return false
150 } else if (event.keyCode === ENTER) { 164 } else if (event.keyCode === ENTER) {
151 this.newSearch = false 165 this.newSearch = false
152 // this.router.navigate(this.keyboardEventsManager.activeItem.result) 166 this.doSearch()
153 return false 167 return false
154 } 168 }
155 } 169 }
156 } 170 }
171
172 doSearch () {
173 const queryParams: Params = {}
174
175 if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
176 Object.assign(queryParams, this.route.snapshot.queryParams)
177 }
178
179 Object.assign(queryParams, { search: this.searchInput.value })
180
181 const o = this.authService.isLoggedIn()
182 ? this.loadUserLanguagesIfNeeded(queryParams)
183 : of(true)
184
185 o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
186 }
187
188 private loadUserLanguagesIfNeeded (queryParams: any) {
189 if (queryParams && queryParams.languageOneOf) return of(queryParams)
190
191 return this.authService.userInformationLoaded
192 .pipe(
193 first(),
194 tap(() => Object.assign(queryParams, { languageOneOf: this.authService.getUser().videoLanguages }))
195 )
196 }
157} 197}