]> BookStack Code Mirror - bookstack/blob - resources/js/components/dropdown-search.js
81fa940c24ca7cf4a38ba66fe7b55e300d746100
[bookstack] / resources / js / components / dropdown-search.js
1 import {debounce} from "../services/util";
2 import {transitionHeight} from "../services/animations";
3
4 class DropdownSearch {
5
6     setup() {
7         this.elem = this.$el;
8         this.searchInput = this.$refs.searchInput;
9         this.loadingElem = this.$refs.loading;
10         this.listContainerElem = this.$refs.listContainer;
11
12         this.localSearchSelector = this.$opts.localSearchSelector;
13         this.url = this.$opts.url;
14
15         this.elem.addEventListener('show', this.onShow.bind(this));
16         this.searchInput.addEventListener('input', this.onSearch.bind(this));
17
18         this.runAjaxSearch = debounce(this.runAjaxSearch, 300, false);
19     }
20
21     onShow() {
22         this.loadList();
23     }
24
25     onSearch() {
26         const input = this.searchInput.value.toLowerCase().trim();
27         if (this.localSearchSelector) {
28             this.runLocalSearch(input);
29         } else {
30             this.toggleLoading(true);
31             this.listContainerElem.innerHTML = '';
32             this.runAjaxSearch(input);
33         }
34     }
35
36     runAjaxSearch(searchTerm) {
37         this.loadList(searchTerm);
38     }
39
40     runLocalSearch(searchTerm) {
41         const listItems = this.listContainerElem.querySelectorAll(this.localSearchSelector);
42         for (let listItem of listItems) {
43             const match = !searchTerm || listItem.textContent.toLowerCase().includes(searchTerm);
44             listItem.style.display = match ? 'flex' : 'none';
45             listItem.classList.toggle('hidden', !match);
46         }
47     }
48
49     async loadList(searchTerm = '') {
50         this.listContainerElem.innerHTML = '';
51         this.toggleLoading(true);
52
53         try {
54             const resp = await window.$http.get(this.getAjaxUrl(searchTerm));
55             const animate = transitionHeight(this.listContainerElem, 80);
56             this.listContainerElem.innerHTML = resp.data;
57             animate();
58         } catch (err) {
59             console.error(err);
60         }
61
62         this.toggleLoading(false);
63         if (this.localSearchSelector) {
64             this.onSearch();
65         }
66     }
67
68     getAjaxUrl(searchTerm = null) {
69         if (!searchTerm) {
70             return this.url;
71         }
72
73         const joiner = this.url.includes('?') ? '&' : '?';
74         return `${this.url}${joiner}search=${encodeURIComponent(searchTerm)}`;
75     }
76
77     toggleLoading(show = false) {
78         this.loadingElem.style.display = show ? 'block' : 'none';
79     }
80
81 }
82
83 export default DropdownSearch;