1 import {onChildEvent} from "../services/dom";
11 this.entityTypes = this.$opts.entityTypes || 'page,book,chapter';
12 this.entityPermission = this.$opts.entityPermission || 'view';
14 this.input = this.$refs.input;
15 this.searchInput = this.$refs.search;
16 this.loading = this.$refs.loading;
17 this.resultsContainer = this.$refs.results;
18 this.addButton = this.$refs.add;
22 this.selectedItemData = null;
24 this.setupListeners();
30 this.elem.addEventListener('click', this.onClick.bind(this));
33 this.searchInput.addEventListener('input', event => {
34 lastSearch = Date.now();
37 if (Date.now() - lastSearch < 199) return;
38 this.searchEntities(this.searchInput.value);
42 this.searchInput.addEventListener('keydown', event => {
43 if (event.keyCode === 13) event.preventDefault();
47 this.addButton.addEventListener('click', event => {
48 if (this.selectedItemData) {
49 this.confirmSelection(this.selectedItemData);
55 // Keyboard navigation
56 onChildEvent(this.$el, '[data-entity-type]', 'keydown', (e, el) => {
57 if (e.ctrlKey && e.code === 'Enter') {
58 const form = this.$el.closest('form');
66 if (e.code === 'ArrowDown') {
67 this.focusAdjacent(true);
69 if (e.code === 'ArrowUp') {
70 this.focusAdjacent(false);
74 this.searchInput.addEventListener('keydown', e => {
75 if (e.code === 'ArrowDown') {
76 this.focusAdjacent(true);
81 focusAdjacent(forward = true) {
82 const items = Array.from(this.resultsContainer.querySelectorAll('[data-entity-type]'));
83 const selectedIndex = items.indexOf(document.activeElement);
84 const newItem = items[selectedIndex+ (forward ? 1 : -1)] || items[0];
91 this.searchInput.value = '';
97 this.searchInput.focus();
101 this.loading.style.display = 'block';
102 this.resultsContainer.style.display = 'none';
106 this.loading.style.display = 'none';
107 this.resultsContainer.style.display = 'block';
111 window.$http.get(this.searchUrl()).then(resp => {
112 this.resultsContainer.innerHTML = resp.data;
118 return `/search/entity-selector?types=${encodeURIComponent(this.entityTypes)}&permission=${encodeURIComponent(this.entityPermission)}`;
121 searchEntities(searchTerm) {
122 this.input.value = '';
123 const url = `${this.searchUrl()}&term=${encodeURIComponent(searchTerm)}`;
124 window.$http.get(url).then(resp => {
125 this.resultsContainer.innerHTML = resp.data;
131 const now = Date.now();
132 const answer = now - this.lastClick < 300;
133 this.lastClick = now;
138 const listItem = event.target.closest('[data-entity-type]');
140 event.preventDefault();
141 event.stopPropagation();
142 this.selectItem(listItem);
147 const isDblClick = this.isDoubleClick();
148 const type = item.getAttribute('data-entity-type');
149 const id = item.getAttribute('data-entity-id');
150 const isSelected = (!item.classList.contains('selected') || isDblClick);
153 this.input.value = isSelected ? `${type}:${id}` : '';
155 const link = item.getAttribute('href');
156 const name = item.querySelector('.entity-list-item-name').textContent;
157 const data = {id: Number(id), name: name, link: link};
160 item.classList.add('selected');
161 this.selectedItemData = data;
163 window.$events.emit('entity-select-change', null)
166 if (!isDblClick && !isSelected) return;
169 this.confirmSelection(data);
172 window.$events.emit('entity-select-change', data)
176 confirmSelection(data) {
177 window.$events.emit('entity-select-confirm', data);
181 const selected = this.elem.querySelectorAll('.selected');
182 for (const selectedElem of selected) {
183 selectedElem.classList.remove('selected', 'primary-background');
185 this.selectedItemData = null;
190 export default EntitySelector;