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