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