1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
const DEFAULTS = {
treshold: 2,
maximumItems: 5,
highlightTyped: true,
highlightClass: 'text-primary',
};
class Autocomplete {
constructor(field, options) {
this.field = field;
this.options = Object.assign({}, DEFAULTS, options);
this.dropdown = null;
field.parentNode.classList.add('dropdown');
field.setAttribute('data-toggle', 'dropdown');
field.classList.add('dropdown-toggle');
const dropdown = ce(`<div class="dropdown-menu" ></div>`);
if (this.options.dropdownClass)
dropdown.classList.add(this.options.dropdownClass);
insertAfter(dropdown, field);
this.dropdown = new bootstrap.Dropdown(field, this.options.dropdownOptions)
field.addEventListener('click', (e) => {
if (this.createItems() === 0) {
e.stopPropagation();
this.dropdown.hide();
}
});
field.addEventListener('input', () => {
if (this.options.onInput)
this.options.onInput(this.field.value);
this.renderIfNeeded();
});
field.addEventListener('keydown', (e) => {
if (e.keyCode === 27) {
this.dropdown.hide();
return;
}
});
}
setData(data) {
this.options.data = data;
}
renderIfNeeded() {
if (this.createItems() > 0)
this.dropdown.show();
else
this.field.click();
}
createItem(lookup, item) {
let label;
if (this.options.highlightTyped) {
const idx = item.label.toLowerCase().indexOf(lookup.toLowerCase());
const className = Array.isArray(this.options.highlightClass) ? this.options.highlightClass.join(' ')
: (typeof this.options.highlightClass == 'string' ? this.options.highlightClass : '')
label = item.label.substring(0, idx)
+ `<span class="${className}">${item.label.substring(idx, idx + lookup.length)}</span>`
+ item.label.substring(idx + lookup.length, item.label.length);
} else
label = item.label;
return ce(`<button type="button" class="dropdown-item" data-value="${item.value}">${label}</button>`);
}
createItems() {
const lookup = this.field.value;
if (lookup.length < this.options.treshold) {
this.dropdown.hide();
return 0;
}
const items = this.field.nextSibling;
items.innerHTML = '';
let count = 0;
for (let i = 0; i < this.options.data.length; i++) {
const {label, value} = this.options.data[i];
const item = {label, value};
if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
items.appendChild(this.createItem(lookup, item));
if (this.options.maximumItems > 0 && ++count >= this.options.maximumItems)
break;
}
}
this.field.nextSibling.querySelectorAll('.dropdown-item').forEach((item) => {
item.addEventListener('click', (e) => {
let dataValue = e.target.getAttribute('data-value');
this.field.value = e.target.innerText;
if (this.options.onSelectItem)
this.options.onSelectItem({
value: e.target.dataset.value,
label: e.target.innerText,
});
this.dropdown.hide();
})
});
return items.childNodes.length;
}
}
/**
* @param html
* @returns {Node}
*/
function ce(html) {
let div = document.createElement('div');
div.innerHTML = html;
return div.firstChild;
}
/**
* @param elem
* @param refElem
* @returns {*}
*/
function insertAfter(elem, refElem) {
return refElem.parentNode.insertBefore(elem, refElem.nextSibling)
}
|