]> BookStack Code Mirror - bookstack/blob - resources/js/components/global-search.js
b3719c8fd02a86c0fe0d14dcc01fd20342509c31
[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
16         this.setupListeners();
17     }
18
19     setupListeners() {
20         const updateSuggestionsDebounced = debounce(this.updateSuggestions.bind(this), 200, false);
21
22         // Handle search input changes
23         this.input.addEventListener('input', () => {
24             const value = this.input.value;
25             if (value.length > 0) {
26                 this.loadingWrap.style.display = 'block';
27                 this.suggestionResultsWrap.style.opacity = '0.5';
28                 updateSuggestionsDebounced(value);
29             }  else {
30                 this.hideSuggestions();
31             }
32         });
33
34         // Allow double click to show auto-click suggestions
35         this.input.addEventListener('dblclick', () => {
36             this.input.setAttribute('autocomplete', 'on');
37             this.input.blur();
38             this.input.focus();
39         })
40     }
41
42     /**
43      * @param {String} search
44      */
45     async updateSuggestions(search) {
46         const {data: results} = await window.$http.get('/ajax/search/entities', {term: search, count: 5});
47         if (!this.input.value) {
48             return;
49         }
50         
51         const resultDom = htmlToDom(results);
52
53         const childrenToTrim = Array.from(resultDom.children).slice(9);
54         for (const child of childrenToTrim) {
55             child.remove();
56         }
57
58         this.suggestionResultsWrap.innerHTML = '';
59         this.suggestionResultsWrap.style.opacity = '1';
60         this.loadingWrap.style.display = 'none';
61         this.suggestionResultsWrap.append(resultDom);
62         if (!this.container.classList.contains('search-active')) {
63             this.showSuggestions();
64         }
65     }
66
67     showSuggestions() {
68         this.container.classList.add('search-active');
69         window.requestAnimationFrame(() => {
70             this.suggestions.classList.add('search-suggestions-animation');
71         })
72     }
73
74     hideSuggestions() {
75         this.container.classList.remove('search-active');
76         this.suggestions.classList.remove('search-suggestions-animation');
77         this.suggestionResultsWrap.innerHTML = '';
78     }
79 }
80
81 export default GlobalSearch;