]> BookStack Code Mirror - bookstack/blob - resources/assets/js/components/entity-selector.js
Implemented new design in entity selector
[bookstack] / resources / assets / js / components / entity-selector.js
1
2 class EntitySelector {
3
4     constructor(elem) {
5         this.elem = elem;
6         this.search = '';
7         this.lastClick = 0;
8
9         const entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
10         const entityPermission = elem.hasAttribute('entity-permission') ? elem.getAttribute('entity-permission') : 'view';
11         this.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}&permission=${encodeURIComponent(entityPermission)}`);
12
13         this.input = elem.querySelector('[entity-selector-input]');
14         this.searchInput = elem.querySelector('[entity-selector-search]');
15         this.loading = elem.querySelector('[entity-selector-loading]');
16         this.resultsContainer = elem.querySelector('[entity-selector-results]');
17
18         this.elem.addEventListener('click', this.onClick.bind(this));
19
20         let lastSearch = 0;
21         this.searchInput.addEventListener('input', event => {
22             lastSearch = Date.now();
23             this.showLoading();
24             setTimeout(() => {
25                 if (Date.now() - lastSearch < 199) return;
26                 this.searchEntities(this.searchInput.value);
27             }, 200);
28         });
29
30         this.searchInput.addEventListener('keydown', event => {
31             if (event.keyCode === 13) event.preventDefault();
32         });
33
34         this.showLoading();
35         this.initialLoad();
36     }
37
38     showLoading() {
39         this.loading.style.display = 'block';
40         this.resultsContainer.style.display = 'none';
41     }
42
43     hideLoading() {
44         this.loading.style.display = 'none';
45         this.resultsContainer.style.display = 'block';
46     }
47
48     initialLoad() {
49         window.$http.get(this.searchUrl).then(resp => {
50             this.resultsContainer.innerHTML = resp.data;
51             this.hideLoading();
52         })
53     }
54
55     searchEntities(searchTerm) {
56         this.input.value = '';
57         let url = `${this.searchUrl}&term=${encodeURIComponent(searchTerm)}`;
58         window.$http.get(url).then(resp => {
59             this.resultsContainer.innerHTML = resp.data;
60             this.hideLoading();
61         });
62     }
63
64     isDoubleClick() {
65         let now = Date.now();
66         let answer = now - this.lastClick < 300;
67         this.lastClick = now;
68         return answer;
69     }
70
71     onClick(event) {
72         const listItem = event.target.closest('[data-entity-type]');
73         if (listItem) {
74             event.preventDefault();
75             event.stopPropagation();
76             this.selectItem(listItem);
77         }
78     }
79
80     selectItem(item) {
81         const isDblClick = this.isDoubleClick();
82         const type = item.getAttribute('data-entity-type');
83         const id = item.getAttribute('data-entity-id');
84         const isSelected = (!item.classList.contains('selected') || isDblClick);
85
86         this.unselectAll();
87         this.input.value = isSelected ? `${type}:${id}` : '';
88
89         if (isSelected) {
90             item.classList.add('selected');
91         } else {
92             window.$events.emit('entity-select-change', null)
93         }
94
95         if (!isDblClick && !isSelected) return;
96
97         const link = item.getAttribute('href');
98         const name = item.querySelector('.entity-list-item-name').textContent;
99         const data = {id: Number(id), name: name, link: link};
100
101         if (isDblClick) {
102             window.$events.emit('entity-select-confirm', data)
103         }
104         if (isSelected) {
105             window.$events.emit('entity-select-change', data)
106         }
107     }
108
109     unselectAll() {
110         let selected = this.elem.querySelectorAll('.selected');
111         for (let selectedElem of selected) {
112             selectedElem.classList.remove('selected', 'primary-background');
113         }
114     }
115
116 }
117
118 export default EntitySelector;