2022-11-20 17:20:31 -05:00
|
|
|
import {htmlToDom} from "../services/dom";
|
|
|
|
import {debounce} from "../services/util";
|
2022-11-21 12:35:19 -05:00
|
|
|
import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
|
2022-11-22 19:12:41 -05:00
|
|
|
import {Component} from "./component";
|
2022-11-20 17:20:31 -05:00
|
|
|
|
2022-11-14 05:24:14 -05:00
|
|
|
/**
|
2022-11-22 19:12:41 -05:00
|
|
|
* Global (header) search box handling.
|
|
|
|
* Mainly to show live results preview.
|
2022-11-14 05:24:14 -05:00
|
|
|
*/
|
2022-11-22 19:12:41 -05:00
|
|
|
export class GlobalSearch extends Component {
|
2022-11-14 05:24:14 -05:00
|
|
|
|
|
|
|
setup() {
|
2022-11-20 16:50:59 -05:00
|
|
|
this.container = this.$el;
|
2022-11-14 05:24:14 -05:00
|
|
|
this.input = this.$refs.input;
|
|
|
|
this.suggestions = this.$refs.suggestions;
|
|
|
|
this.suggestionResultsWrap = this.$refs.suggestionResults;
|
2022-11-20 17:20:31 -05:00
|
|
|
this.loadingWrap = this.$refs.loading;
|
2022-11-21 05:29:12 -05:00
|
|
|
this.button = this.$refs.button;
|
2022-11-14 05:24:14 -05:00
|
|
|
|
|
|
|
this.setupListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
setupListeners() {
|
2022-11-20 17:20:31 -05:00
|
|
|
const updateSuggestionsDebounced = debounce(this.updateSuggestions.bind(this), 200, false);
|
|
|
|
|
|
|
|
// Handle search input changes
|
2022-11-14 05:24:14 -05:00
|
|
|
this.input.addEventListener('input', () => {
|
|
|
|
const value = this.input.value;
|
|
|
|
if (value.length > 0) {
|
2022-11-20 17:20:31 -05:00
|
|
|
this.loadingWrap.style.display = 'block';
|
|
|
|
this.suggestionResultsWrap.style.opacity = '0.5';
|
|
|
|
updateSuggestionsDebounced(value);
|
2022-11-14 05:24:14 -05:00
|
|
|
} else {
|
|
|
|
this.hideSuggestions();
|
|
|
|
}
|
|
|
|
});
|
2022-11-20 17:20:31 -05:00
|
|
|
|
|
|
|
// Allow double click to show auto-click suggestions
|
|
|
|
this.input.addEventListener('dblclick', () => {
|
|
|
|
this.input.setAttribute('autocomplete', 'on');
|
2022-11-21 05:29:12 -05:00
|
|
|
this.button.focus();
|
2022-11-20 17:20:31 -05:00
|
|
|
this.input.focus();
|
2022-11-21 12:35:19 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
new KeyboardNavigationHandler(this.container, () => {
|
|
|
|
this.hideSuggestions();
|
|
|
|
});
|
2022-11-14 05:24:14 -05:00
|
|
|
}
|
|
|
|
|
2022-11-20 17:20:31 -05:00
|
|
|
/**
|
|
|
|
* @param {String} search
|
|
|
|
*/
|
2022-11-14 05:24:14 -05:00
|
|
|
async updateSuggestions(search) {
|
2022-11-21 05:29:12 -05:00
|
|
|
const {data: results} = await window.$http.get('/search/suggest', {term: search});
|
2022-11-20 17:20:31 -05:00
|
|
|
if (!this.input.value) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-14 05:24:14 -05:00
|
|
|
const resultDom = htmlToDom(results);
|
|
|
|
|
|
|
|
this.suggestionResultsWrap.innerHTML = '';
|
2022-11-20 17:20:31 -05:00
|
|
|
this.suggestionResultsWrap.style.opacity = '1';
|
|
|
|
this.loadingWrap.style.display = 'none';
|
2022-11-14 05:24:14 -05:00
|
|
|
this.suggestionResultsWrap.append(resultDom);
|
2022-11-20 16:50:59 -05:00
|
|
|
if (!this.container.classList.contains('search-active')) {
|
|
|
|
this.showSuggestions();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
showSuggestions() {
|
|
|
|
this.container.classList.add('search-active');
|
|
|
|
window.requestAnimationFrame(() => {
|
|
|
|
this.suggestions.classList.add('search-suggestions-animation');
|
|
|
|
})
|
2022-11-14 05:24:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
hideSuggestions() {
|
2022-11-20 16:50:59 -05:00
|
|
|
this.container.classList.remove('search-active');
|
|
|
|
this.suggestions.classList.remove('search-suggestions-animation');
|
2022-11-14 05:24:14 -05:00
|
|
|
this.suggestionResultsWrap.innerHTML = '';
|
|
|
|
}
|
2022-11-22 19:12:41 -05:00
|
|
|
}
|