]> BookStack Code Mirror - bookstack/blob - resources/js/components/global-search.js
c940ad98389d153818ab8d56016b3715128e35ff
[bookstack] / resources / js / components / global-search.js
1 import {htmlToDom} from "../services/dom";
2 import {debounce} from "../services/util";
3
4 /**
5  * @extends {Component}
6  */
7 class GlobalSearch {
8
9     setup() {
10         this.container = this.$el;
11         this.input = this.$refs.input;
12         this.suggestions = this.$refs.suggestions;
13         this.suggestionResultsWrap = this.$refs.suggestionResults;
14         this.loadingWrap = this.$refs.loading;
15         this.button = this.$refs.button;
16
17         this.setupListeners();
18     }
19
20     setupListeners() {
21         const updateSuggestionsDebounced = debounce(this.updateSuggestions.bind(this), 200, false);
22
23         // Handle search input changes
24         this.input.addEventListener('input', () => {
25             const value = this.input.value;
26             if (value.length > 0) {
27                 this.loadingWrap.style.display = 'block';
28                 this.suggestionResultsWrap.style.opacity = '0.5';
29                 updateSuggestionsDebounced(value);
30             }  else {
31                 this.hideSuggestions();
32             }
33         });
34
35         // Allow double click to show auto-click suggestions
36         this.input.addEventListener('dblclick', () => {
37             this.input.setAttribute('autocomplete', 'on');
38             this.button.focus();
39             this.input.focus();
40         })
41     }
42
43     /**
44      * @param {String} search
45      */
46     async updateSuggestions(search) {
47         const {data: results} = await window.$http.get('/search/suggest', {term: search});
48         if (!this.input.value) {
49             return;
50         }
51         
52         const resultDom = htmlToDom(results);
53
54         this.suggestionResultsWrap.innerHTML = '';
55         this.suggestionResultsWrap.style.opacity = '1';
56         this.loadingWrap.style.display = 'none';
57         this.suggestionResultsWrap.append(resultDom);
58         if (!this.container.classList.contains('search-active')) {
59             this.showSuggestions();
60         }
61     }
62
63     showSuggestions() {
64         this.container.classList.add('search-active');
65         window.requestAnimationFrame(() => {
66             this.suggestions.classList.add('search-suggestions-animation');
67         })
68     }
69
70     hideSuggestions() {
71         this.container.classList.remove('search-active');
72         this.suggestions.classList.remove('search-suggestions-animation');
73         this.suggestionResultsWrap.innerHTML = '';
74     }
75 }
76
77 export default GlobalSearch;