slim-select 2.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +8 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/render.d.ts +10 -3
  4. package/dist/select.d.ts +6 -6
  5. package/dist/settings.d.ts +0 -3
  6. package/dist/slimselect.cjs.js +202 -67
  7. package/dist/slimselect.css +1 -1
  8. package/dist/slimselect.css.map +1 -1
  9. package/dist/slimselect.es.js +202 -67
  10. package/dist/slimselect.global.js +202 -67
  11. package/dist/slimselect.js +202 -67
  12. package/dist/slimselect.min.js +1 -1
  13. package/dist/slimselect.umd.js +202 -67
  14. package/dist/slimselect.umd.min.js +1 -1
  15. package/dist/store.d.ts +5 -0
  16. package/docs/assets/data.js +7 -3
  17. package/docs/assets/home.css +1 -1
  18. package/docs/assets/home.js +1 -1
  19. package/docs/assets/index.css +1 -1
  20. package/docs/assets/index.js +7 -7
  21. package/docs/assets/index2.js +119 -35
  22. package/docs/assets/index3.js +39 -23
  23. package/docs/assets/index4.js +1 -1
  24. package/docs/assets/index5.js +147 -9
  25. package/docs/assets/install.js +4 -4
  26. package/docs/assets/selects.js +1 -1
  27. package/package.json +11 -3
  28. package/src/docs/app.vue +6 -5
  29. package/src/docs/{images → assets/images}/check-mark.svg +0 -0
  30. package/src/docs/{images → assets/images}/chrome.svg +0 -0
  31. package/src/docs/{images → assets/images}/firefox.svg +0 -0
  32. package/src/docs/{images → assets/images}/github.png +0 -0
  33. package/src/docs/{images → assets/images}/ie.svg +0 -0
  34. package/src/docs/{images → assets/images}/npm.png +0 -0
  35. package/src/docs/{images → assets/images}/opera.svg +0 -0
  36. package/src/docs/{images → assets/images}/safari.svg +0 -0
  37. package/src/docs/assets/scss/misc.scss +7 -0
  38. package/src/docs/env.d.ts +1 -0
  39. package/src/docs/pages/data.vue +4 -0
  40. package/src/docs/pages/events/addable.vue +22 -6
  41. package/src/docs/pages/events/before_after_change.vue +15 -1
  42. package/src/docs/pages/events/search.vue +31 -16
  43. package/src/docs/pages/frameworks/vue.vue +375 -7
  44. package/src/docs/pages/home.vue +104 -57
  45. package/src/docs/pages/methods/get_data.vue +2 -1
  46. package/src/docs/pages/methods/open_close.vue +1 -1
  47. package/src/docs/pages/settings/closable.vue +128 -0
  48. package/src/docs/pages/settings/index.vue +6 -3
  49. package/src/docs/pages/settings/select_all.vue +88 -0
  50. package/src/slim-select/index.ts +4 -2
  51. package/src/slim-select/render.ts +247 -59
  52. package/src/slim-select/rollup.config.mjs +5 -0
  53. package/src/slim-select/select.ts +48 -31
  54. package/src/slim-select/settings.ts +0 -4
  55. package/src/slim-select/slimselect.scss +112 -11
  56. package/src/slim-select/store.ts +19 -1
  57. package/src/vue/README.md +48 -0
  58. package/src/vue/dist/slimselectvue.es.js +1752 -0
  59. package/src/vue/dist/slimselectvue.global.js +1755 -0
  60. package/src/vue/dist/slimselectvue.ssr.js +1754 -0
  61. package/src/vue/hello.ts +5 -0
  62. package/src/vue/package.json +28 -0
  63. package/src/vue/rollup.config.mjs +44 -0
  64. package/src/vue/slimselect.vue +39 -5
  65. package/src/vue/tsconfig.json +14 -0
  66. package/src/docs/pages/settings/select_by_group.vue +0 -46
@@ -0,0 +1,1752 @@
1
+ import { defineComponent, openBlock, createElementBlock, renderSlot } from 'vue';
2
+
3
+ function generateID() {
4
+ return Math.random().toString(36).substring(2, 10);
5
+ }
6
+ function hasClassInTree(element, className) {
7
+ function hasClass(e, c) {
8
+ if (c && e && e.classList && e.classList.contains(c)) {
9
+ return e;
10
+ }
11
+ if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {
12
+ return e;
13
+ }
14
+ return null;
15
+ }
16
+ function parentByClass(e, c) {
17
+ if (!e || e === document) {
18
+ return null;
19
+ }
20
+ else if (hasClass(e, c)) {
21
+ return e;
22
+ }
23
+ else {
24
+ return parentByClass(e.parentNode, c);
25
+ }
26
+ }
27
+ return hasClass(element, className) || parentByClass(element, className);
28
+ }
29
+ function debounce(func, wait = 50, immediate = false) {
30
+ let timeout;
31
+ return function (...args) {
32
+ const context = self;
33
+ const later = () => {
34
+ timeout = null;
35
+ if (!immediate) {
36
+ func.apply(context, args);
37
+ }
38
+ };
39
+ const callNow = immediate && !timeout;
40
+ clearTimeout(timeout);
41
+ timeout = setTimeout(later, wait);
42
+ if (callNow) {
43
+ func.apply(context, args);
44
+ }
45
+ };
46
+ }
47
+ function kebabCase(str) {
48
+ const result = str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
49
+ return str[0] === str[0].toUpperCase() ? result.substring(1) : result;
50
+ }
51
+
52
+ class Optgroup {
53
+ constructor(optgroup) {
54
+ this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id;
55
+ this.label = optgroup.label || '';
56
+ this.selectAll = optgroup.selectAll === undefined ? false : optgroup.selectAll;
57
+ this.closable = optgroup.closable || 'off';
58
+ this.options = [];
59
+ if (optgroup.options) {
60
+ for (const o of optgroup.options) {
61
+ this.options.push(new Option(o));
62
+ }
63
+ }
64
+ }
65
+ }
66
+ class Option {
67
+ constructor(option) {
68
+ this.id = !option.id || option.id === '' ? generateID() : option.id;
69
+ this.value = option.value === undefined ? option.text : option.value;
70
+ this.text = option.text || '';
71
+ this.html = option.html || '';
72
+ this.selected = option.selected !== undefined ? option.selected : false;
73
+ this.display = option.display !== undefined ? option.display : true;
74
+ this.disabled = option.disabled !== undefined ? option.disabled : false;
75
+ this.mandatory = option.mandatory !== undefined ? option.mandatory : false;
76
+ this.placeholder = option.placeholder !== undefined ? option.placeholder : false;
77
+ this.class = option.class || '';
78
+ this.style = option.style || '';
79
+ this.data = option.data || {};
80
+ }
81
+ }
82
+ class Store {
83
+ constructor(type, data) {
84
+ this.selectType = 'single';
85
+ this.data = [];
86
+ this.selectType = type;
87
+ this.setData(data);
88
+ }
89
+ validateDataArray(data) {
90
+ if (!Array.isArray(data)) {
91
+ return new Error('Data must be an array');
92
+ }
93
+ for (let dataObj of data) {
94
+ if (dataObj instanceof Optgroup || 'label' in dataObj) {
95
+ if (!('label' in dataObj)) {
96
+ return new Error('Optgroup must have a label');
97
+ }
98
+ if ('options' in dataObj && dataObj.options) {
99
+ for (let option of dataObj.options) {
100
+ return this.validateOption(option);
101
+ }
102
+ }
103
+ }
104
+ else if (dataObj instanceof Option || 'text' in dataObj) {
105
+ return this.validateOption(dataObj);
106
+ }
107
+ else {
108
+ return new Error('Data object must be a valid optgroup or option');
109
+ }
110
+ }
111
+ return null;
112
+ }
113
+ validateOption(option) {
114
+ if (!('text' in option)) {
115
+ return new Error('Option must have a text');
116
+ }
117
+ return null;
118
+ }
119
+ partialToFullData(data) {
120
+ let dataFinal = [];
121
+ data.forEach((dataObj) => {
122
+ if (dataObj instanceof Optgroup || 'label' in dataObj) {
123
+ let optOptions = [];
124
+ if ('options' in dataObj && dataObj.options) {
125
+ dataObj.options.forEach((option) => {
126
+ optOptions.push(new Option(option));
127
+ });
128
+ }
129
+ if (optOptions.length > 0) {
130
+ dataFinal.push(new Optgroup(dataObj));
131
+ }
132
+ }
133
+ if (dataObj instanceof Option || 'text' in dataObj) {
134
+ dataFinal.push(new Option(dataObj));
135
+ }
136
+ });
137
+ return dataFinal;
138
+ }
139
+ setData(data) {
140
+ this.data = this.partialToFullData(data);
141
+ if (this.selectType === 'single') {
142
+ this.setSelectedBy('value', this.getSelected());
143
+ }
144
+ }
145
+ getData() {
146
+ return this.filter(null, true);
147
+ }
148
+ getDataOptions() {
149
+ return this.filter(null, false);
150
+ }
151
+ addOption(option) {
152
+ this.setData(this.getData().concat(new Option(option)));
153
+ }
154
+ setSelectedBy(selectedType, selectedValues) {
155
+ let firstOption = null;
156
+ let hasSelected = false;
157
+ for (let dataObj of this.data) {
158
+ if (dataObj instanceof Optgroup) {
159
+ for (let option of dataObj.options) {
160
+ if (!firstOption) {
161
+ firstOption = option;
162
+ }
163
+ option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
164
+ if (option.selected && this.selectType === 'single') {
165
+ hasSelected = true;
166
+ }
167
+ }
168
+ }
169
+ if (dataObj instanceof Option) {
170
+ if (!firstOption) {
171
+ firstOption = dataObj;
172
+ }
173
+ dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
174
+ if (dataObj.selected && this.selectType === 'single') {
175
+ hasSelected = true;
176
+ }
177
+ }
178
+ }
179
+ if (this.selectType === 'single' && firstOption && !hasSelected) {
180
+ firstOption.selected = true;
181
+ }
182
+ }
183
+ getSelected() {
184
+ let selectedOptions = this.getSelectedOptions();
185
+ let selectedValues = [];
186
+ selectedOptions.forEach((option) => {
187
+ selectedValues.push(option.value);
188
+ });
189
+ return selectedValues;
190
+ }
191
+ getSelectedOptions() {
192
+ return this.filter((opt) => {
193
+ return opt.selected;
194
+ }, false);
195
+ }
196
+ getSelectedIDs() {
197
+ let selectedOptions = this.getSelectedOptions();
198
+ let selectedIDs = [];
199
+ selectedOptions.forEach((op) => {
200
+ selectedIDs.push(op.id);
201
+ });
202
+ return selectedIDs;
203
+ }
204
+ getOptgroupByID(id) {
205
+ for (let dataObj of this.data) {
206
+ if (dataObj instanceof Optgroup && dataObj.id === id) {
207
+ return dataObj;
208
+ }
209
+ }
210
+ return null;
211
+ }
212
+ getOptionByID(id) {
213
+ let options = this.filter((opt) => {
214
+ return opt.id === id;
215
+ }, false);
216
+ return options.length ? options[0] : null;
217
+ }
218
+ search(search, searchFilter) {
219
+ search = search.trim();
220
+ if (search === '') {
221
+ return this.getData();
222
+ }
223
+ return this.filter((opt) => {
224
+ return searchFilter(opt, search);
225
+ }, true);
226
+ }
227
+ filter(filter, includeOptgroup) {
228
+ const dataSearch = [];
229
+ this.data.forEach((dataObj) => {
230
+ if (dataObj instanceof Optgroup) {
231
+ if (!includeOptgroup) {
232
+ dataObj.options.forEach((option) => {
233
+ if (filter && filter(option)) {
234
+ dataSearch.push(option);
235
+ }
236
+ });
237
+ }
238
+ else {
239
+ let optOptions = [];
240
+ dataObj.options.forEach((option) => {
241
+ if (!filter || filter(option)) {
242
+ optOptions.push(new Option(option));
243
+ }
244
+ });
245
+ if (optOptions.length > 0) {
246
+ dataSearch.push(new Optgroup(dataObj));
247
+ }
248
+ }
249
+ }
250
+ if (dataObj instanceof Option) {
251
+ if (!filter || filter(dataObj)) {
252
+ dataSearch.push(new Option(dataObj));
253
+ }
254
+ }
255
+ });
256
+ return dataSearch;
257
+ }
258
+ }
259
+
260
+ class Render {
261
+ constructor(settings, store, callbacks) {
262
+ this.classes = {
263
+ main: 'ss-main',
264
+ placeholder: 'ss-placeholder',
265
+ values: 'ss-values',
266
+ single: 'ss-single',
267
+ value: 'ss-value',
268
+ valueText: 'ss-value-text',
269
+ valueDelete: 'ss-value-delete',
270
+ valueOut: 'ss-value-out',
271
+ deselect: 'ss-deselect',
272
+ deselectPath: 'M10,10 L90,90 M10,90 L90,10',
273
+ arrow: 'ss-arrow',
274
+ arrowClose: 'M10,30 L50,70 L90,30',
275
+ arrowOpen: 'M10,70 L50,30 L90,70',
276
+ content: 'ss-content',
277
+ openAbove: 'ss-open-above',
278
+ openBelow: 'ss-open-below',
279
+ search: 'ss-search',
280
+ searchHighlighter: 'ss-search-highlight',
281
+ searching: 'ss-searching',
282
+ addable: 'ss-addable',
283
+ addablePath: 'M50,10 L50,90 M10,50 L90,50',
284
+ list: 'ss-list',
285
+ optgroup: 'ss-optgroup',
286
+ optgroupLabel: 'ss-optgroup-label',
287
+ optgroupLabelText: 'ss-optgroup-label-text',
288
+ optgroupActions: 'ss-optgroup-actions',
289
+ optgroupSelectAll: 'ss-selectall',
290
+ optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
291
+ optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
292
+ optgroupClosable: 'ss-closable',
293
+ option: 'ss-option',
294
+ optionDelete: 'M10,10 L90,90 M10,90 L90,10',
295
+ highlighted: 'ss-highlighted',
296
+ open: 'ss-open',
297
+ close: 'ss-close',
298
+ selected: 'ss-selected',
299
+ error: 'ss-error',
300
+ disabled: 'ss-disabled',
301
+ hide: 'ss-hide',
302
+ };
303
+ this.store = store;
304
+ this.settings = settings;
305
+ this.callbacks = callbacks;
306
+ this.main = this.mainDiv();
307
+ this.content = this.contentDiv();
308
+ this.settings.contentLocation.appendChild(this.content.main);
309
+ }
310
+ enable() {
311
+ this.main.main.classList.remove(this.classes.disabled);
312
+ this.content.search.input.disabled = false;
313
+ }
314
+ disable() {
315
+ this.main.main.classList.add(this.classes.disabled);
316
+ this.content.search.input.disabled = true;
317
+ }
318
+ open() {
319
+ this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
320
+ this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
321
+ this.moveContent();
322
+ this.renderOptions(this.store.getData());
323
+ if (this.settings.contentPosition === 'relative') {
324
+ this.moveContentBelow();
325
+ }
326
+ else if (this.settings.openPosition.toLowerCase() === 'up') {
327
+ this.moveContentAbove();
328
+ }
329
+ else if (this.settings.openPosition.toLowerCase() === 'down') {
330
+ this.moveContentBelow();
331
+ }
332
+ else {
333
+ if (this.putContent(this.content.main, this.settings.isOpen) === 'up') {
334
+ this.moveContentAbove();
335
+ }
336
+ else {
337
+ this.moveContentBelow();
338
+ }
339
+ }
340
+ const selectedOptions = this.store.getSelectedOptions();
341
+ if (selectedOptions.length) {
342
+ const selectedId = selectedOptions[selectedOptions.length - 1].id;
343
+ const selectedOption = this.content.list.querySelector('[data-id="' + selectedId + '"]');
344
+ if (selectedOption) {
345
+ this.ensureElementInView(this.content.list, selectedOption);
346
+ }
347
+ }
348
+ }
349
+ close() {
350
+ this.main.main.classList.remove(this.classes.openAbove);
351
+ this.main.main.classList.remove(this.classes.openBelow);
352
+ this.content.main.classList.remove(this.classes.openAbove);
353
+ this.content.main.classList.remove(this.classes.openBelow);
354
+ this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
355
+ }
356
+ mainDiv() {
357
+ const main = document.createElement('div');
358
+ main.tabIndex = 0;
359
+ main.style.cssText = this.settings.style !== '' ? this.settings.style : '';
360
+ main.className = '';
361
+ main.classList.add(this.settings.id);
362
+ main.classList.add(this.classes.main);
363
+ if (this.settings.class) {
364
+ for (const c of this.settings.class) {
365
+ if (c.trim() !== '') {
366
+ main.classList.add(c.trim());
367
+ }
368
+ }
369
+ }
370
+ main.onfocus = () => {
371
+ if (this.settings.triggerFocus) {
372
+ this.callbacks.open();
373
+ }
374
+ };
375
+ main.onkeydown = (e) => {
376
+ switch (e.key) {
377
+ case 'ArrowUp':
378
+ case 'ArrowDown':
379
+ this.callbacks.open();
380
+ e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
381
+ return false;
382
+ case 'Tab':
383
+ this.callbacks.close();
384
+ return true;
385
+ case 'Enter':
386
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
387
+ if (highlighted) {
388
+ highlighted.click();
389
+ }
390
+ return false;
391
+ case 'Escape':
392
+ this.callbacks.close();
393
+ return false;
394
+ }
395
+ };
396
+ main.onclick = (e) => {
397
+ if (!this.settings.isEnabled) {
398
+ return;
399
+ }
400
+ this.settings.isOpen ? this.callbacks.close() : this.callbacks.open();
401
+ };
402
+ const values = document.createElement('div');
403
+ values.classList.add(this.classes.values);
404
+ main.appendChild(values);
405
+ const deselect = document.createElement('div');
406
+ deselect.classList.add(this.classes.deselect);
407
+ if (!this.settings.allowDeselect || this.settings.isMultiple) {
408
+ deselect.classList.add(this.classes.hide);
409
+ }
410
+ deselect.onclick = (e) => {
411
+ e.stopPropagation();
412
+ if (!this.settings.isEnabled) {
413
+ return;
414
+ }
415
+ let shouldDelete = true;
416
+ const before = this.store.getSelectedOptions();
417
+ const after = [];
418
+ if (this.callbacks.beforeChange) {
419
+ shouldDelete = this.callbacks.beforeChange(after, before) === true;
420
+ }
421
+ if (shouldDelete) {
422
+ this.callbacks.setSelected(['']);
423
+ if (this.settings.closeOnSelect) {
424
+ this.callbacks.close();
425
+ }
426
+ if (this.callbacks.afterChange) {
427
+ this.callbacks.afterChange(after);
428
+ }
429
+ }
430
+ };
431
+ const deselectSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
432
+ deselectSvg.setAttribute('viewBox', '0 0 100 100');
433
+ const deselectPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
434
+ deselectPath.setAttribute('d', this.classes.deselectPath);
435
+ deselectSvg.appendChild(deselectPath);
436
+ deselect.appendChild(deselectSvg);
437
+ main.appendChild(deselect);
438
+ const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
439
+ arrow.classList.add(this.classes.arrow);
440
+ arrow.setAttribute('viewBox', '0 0 100 100');
441
+ const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
442
+ arrowPath.setAttribute('d', this.classes.arrowClose);
443
+ if (this.settings.alwaysOpen) {
444
+ arrow.classList.add(this.classes.hide);
445
+ }
446
+ arrow.appendChild(arrowPath);
447
+ main.appendChild(arrow);
448
+ return {
449
+ main: main,
450
+ values: values,
451
+ deselect: {
452
+ main: deselect,
453
+ svg: deselectSvg,
454
+ path: deselectPath,
455
+ },
456
+ arrow: {
457
+ main: arrow,
458
+ path: arrowPath,
459
+ },
460
+ };
461
+ }
462
+ mainFocus(trigger) {
463
+ if (!trigger) {
464
+ this.settings.triggerFocus = false;
465
+ }
466
+ this.main.main.focus({ preventScroll: true });
467
+ this.settings.triggerFocus = true;
468
+ }
469
+ placeholder() {
470
+ const placeholderOption = this.store.filter((o) => o.placeholder, false);
471
+ let placeholderText = this.settings.placeholderText;
472
+ if (placeholderOption.length) {
473
+ if (placeholderOption[0].html !== '') {
474
+ placeholderText = placeholderOption[0].html;
475
+ }
476
+ else if (placeholderOption[0].text !== '') {
477
+ placeholderText = placeholderOption[0].text;
478
+ }
479
+ }
480
+ const placeholder = document.createElement('div');
481
+ placeholder.classList.add(this.classes.placeholder);
482
+ placeholder.innerHTML = placeholderText;
483
+ return placeholder;
484
+ }
485
+ renderValues() {
486
+ if (!this.settings.isMultiple) {
487
+ this.renderSingleValue();
488
+ return;
489
+ }
490
+ this.renderMultipleValues();
491
+ }
492
+ renderSingleValue() {
493
+ const selected = this.store.filter((o) => {
494
+ return o.selected && !o.placeholder;
495
+ }, false);
496
+ const selectedSingle = selected.length > 0 ? selected[0] : null;
497
+ if (!selectedSingle) {
498
+ this.main.values.innerHTML = this.placeholder().outerHTML;
499
+ }
500
+ else {
501
+ const singleValue = document.createElement('div');
502
+ singleValue.classList.add(this.classes.single);
503
+ singleValue.innerHTML = selectedSingle.html ? selectedSingle.html : selectedSingle.text;
504
+ this.main.values.innerHTML = singleValue.outerHTML;
505
+ }
506
+ if (!this.settings.allowDeselect || !selected.length) {
507
+ this.main.deselect.main.classList.add(this.classes.hide);
508
+ }
509
+ else {
510
+ this.main.deselect.main.classList.remove(this.classes.hide);
511
+ }
512
+ }
513
+ renderMultipleValues() {
514
+ let currentNodes = this.main.values.childNodes;
515
+ let selectedOptions = this.store.filter((opt) => {
516
+ return opt.selected && opt.display;
517
+ }, false);
518
+ if (selectedOptions.length === 0) {
519
+ this.main.values.innerHTML = this.placeholder().outerHTML;
520
+ return;
521
+ }
522
+ else {
523
+ const placeholder = this.main.values.querySelector('.' + this.classes.placeholder);
524
+ if (placeholder) {
525
+ placeholder.remove();
526
+ }
527
+ }
528
+ let removeNodes = [];
529
+ for (let i = 0; i < currentNodes.length; i++) {
530
+ const node = currentNodes[i];
531
+ const id = node.getAttribute('data-id');
532
+ if (id) {
533
+ const found = selectedOptions.filter((opt) => {
534
+ return opt.id === id;
535
+ }, false);
536
+ if (!found.length) {
537
+ removeNodes.push(node);
538
+ }
539
+ }
540
+ }
541
+ for (const n of removeNodes) {
542
+ n.classList.add(this.classes.valueOut);
543
+ setTimeout(() => {
544
+ this.main.values.removeChild(n);
545
+ }, 100);
546
+ }
547
+ currentNodes = this.main.values.childNodes;
548
+ for (let d = 0; d < selectedOptions.length; d++) {
549
+ let shouldAdd = true;
550
+ for (let i = 0; i < currentNodes.length; i++) {
551
+ if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {
552
+ shouldAdd = false;
553
+ }
554
+ }
555
+ if (shouldAdd) {
556
+ if (currentNodes.length === 0) {
557
+ this.main.values.appendChild(this.multipleValue(selectedOptions[d]));
558
+ }
559
+ else if (d === 0) {
560
+ this.main.values.insertBefore(this.multipleValue(selectedOptions[d]), currentNodes[d]);
561
+ }
562
+ else {
563
+ currentNodes[d - 1].insertAdjacentElement('afterend', this.multipleValue(selectedOptions[d]));
564
+ }
565
+ }
566
+ }
567
+ }
568
+ multipleValue(option) {
569
+ const value = document.createElement('div');
570
+ value.classList.add(this.classes.value);
571
+ value.dataset.id = option.id;
572
+ const text = document.createElement('div');
573
+ text.classList.add(this.classes.valueText);
574
+ text.innerHTML = option.text;
575
+ value.appendChild(text);
576
+ if (!option.mandatory) {
577
+ const deleteDiv = document.createElement('div');
578
+ deleteDiv.classList.add(this.classes.valueDelete);
579
+ deleteDiv.onclick = (e) => {
580
+ e.preventDefault();
581
+ e.stopPropagation();
582
+ let shouldDelete = true;
583
+ const before = this.store.getSelectedOptions();
584
+ const after = before.filter((o) => {
585
+ return o.selected && o.id !== option.id;
586
+ }, true);
587
+ if (this.settings.minSelected && after.length < this.settings.minSelected) {
588
+ return;
589
+ }
590
+ if (this.callbacks.beforeChange) {
591
+ shouldDelete = this.callbacks.beforeChange(after, before) === true;
592
+ }
593
+ if (shouldDelete) {
594
+ let selectedValues = [];
595
+ for (const o of after) {
596
+ if (o instanceof Optgroup) {
597
+ for (const c of o.options) {
598
+ selectedValues.push(c.value);
599
+ }
600
+ }
601
+ if (o instanceof Option) {
602
+ selectedValues.push(o.value);
603
+ }
604
+ }
605
+ this.callbacks.setSelected(selectedValues);
606
+ if (this.settings.closeOnSelect) {
607
+ this.callbacks.close();
608
+ }
609
+ if (this.callbacks.afterChange) {
610
+ this.callbacks.afterChange(after);
611
+ }
612
+ }
613
+ };
614
+ const deleteSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
615
+ deleteSvg.setAttribute('viewBox', '0 0 100 100');
616
+ const deletePath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
617
+ deletePath.setAttribute('d', this.classes.optionDelete);
618
+ deleteSvg.appendChild(deletePath);
619
+ deleteDiv.appendChild(deleteSvg);
620
+ value.appendChild(deleteDiv);
621
+ }
622
+ return value;
623
+ }
624
+ contentDiv() {
625
+ const main = document.createElement('div');
626
+ main.classList.add(this.classes.content);
627
+ main.dataset.id = this.settings.id;
628
+ if (this.settings.style !== '') {
629
+ main.style.cssText = this.settings.style;
630
+ }
631
+ if (this.settings.contentPosition === 'relative') {
632
+ main.classList.add('ss-' + this.settings.contentPosition);
633
+ }
634
+ if (this.settings.class.length) {
635
+ for (const c of this.settings.class) {
636
+ if (c.trim() !== '') {
637
+ main.classList.add(c.trim());
638
+ }
639
+ }
640
+ }
641
+ const search = this.searchDiv();
642
+ main.appendChild(search.main);
643
+ const list = this.listDiv();
644
+ main.appendChild(list);
645
+ return {
646
+ main: main,
647
+ search: search,
648
+ list: list,
649
+ };
650
+ }
651
+ moveContent() {
652
+ if (this.settings.contentPosition === 'relative') {
653
+ return;
654
+ }
655
+ const containerRect = this.main.main.getBoundingClientRect();
656
+ this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
657
+ this.content.main.style.left = containerRect.left + window.scrollX + 'px';
658
+ this.content.main.style.width = containerRect.width + 'px';
659
+ }
660
+ searchDiv() {
661
+ const main = document.createElement('div');
662
+ const input = document.createElement('input');
663
+ const addable = document.createElement('div');
664
+ main.classList.add(this.classes.search);
665
+ const searchReturn = {
666
+ main,
667
+ input,
668
+ };
669
+ if (!this.settings.showSearch) {
670
+ main.classList.add(this.classes.hide);
671
+ input.readOnly = true;
672
+ }
673
+ input.type = 'search';
674
+ input.placeholder = this.settings.searchPlaceholder;
675
+ input.tabIndex = -1;
676
+ input.setAttribute('aria-label', this.settings.searchPlaceholder);
677
+ input.setAttribute('autocapitalize', 'off');
678
+ input.setAttribute('autocomplete', 'off');
679
+ input.setAttribute('autocorrect', 'off');
680
+ input.oninput = debounce((e) => {
681
+ this.callbacks.search(e.target.value);
682
+ }, 100);
683
+ input.onkeydown = (e) => {
684
+ switch (e.key) {
685
+ case 'ArrowUp':
686
+ case 'ArrowDown':
687
+ this.callbacks.open();
688
+ e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
689
+ return false;
690
+ case 'Tab':
691
+ this.callbacks.close();
692
+ return true;
693
+ case 'Escape':
694
+ this.callbacks.close();
695
+ return false;
696
+ case 'Enter':
697
+ if (this.callbacks.addable && e.ctrlKey) {
698
+ addable.click();
699
+ }
700
+ else {
701
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
702
+ if (highlighted) {
703
+ highlighted.click();
704
+ }
705
+ }
706
+ return false;
707
+ }
708
+ };
709
+ input.onfocus = () => {
710
+ if (this.settings.isOpen) {
711
+ return;
712
+ }
713
+ this.callbacks.open();
714
+ };
715
+ main.appendChild(input);
716
+ if (this.callbacks.addable) {
717
+ addable.classList.add(this.classes.addable);
718
+ const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
719
+ plus.setAttribute('viewBox', '0 0 100 100');
720
+ const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
721
+ plusPath.setAttribute('d', this.classes.addablePath);
722
+ plus.appendChild(plusPath);
723
+ addable.appendChild(plus);
724
+ addable.onclick = (e) => {
725
+ e.preventDefault();
726
+ e.stopPropagation();
727
+ if (!this.callbacks.addable) {
728
+ return;
729
+ }
730
+ const inputValue = this.content.search.input.value.trim();
731
+ if (inputValue === '') {
732
+ this.content.search.input.focus();
733
+ return;
734
+ }
735
+ const runFinish = (oo) => {
736
+ let newOption = new Option(oo);
737
+ this.callbacks.addOption(newOption);
738
+ if (this.settings.isMultiple) {
739
+ let values = this.store.getSelected();
740
+ values.push(newOption.value);
741
+ this.callbacks.setSelected(values);
742
+ }
743
+ else {
744
+ this.callbacks.setSelected([newOption.value]);
745
+ }
746
+ this.callbacks.search('');
747
+ if (this.settings.closeOnSelect) {
748
+ setTimeout(() => {
749
+ this.callbacks.close();
750
+ }, 100);
751
+ }
752
+ };
753
+ const addableValue = this.callbacks.addable(inputValue);
754
+ if (addableValue instanceof Promise) {
755
+ addableValue.then((value) => {
756
+ if (typeof value === 'string') {
757
+ runFinish({
758
+ text: value,
759
+ value: value,
760
+ });
761
+ }
762
+ else {
763
+ runFinish(value);
764
+ }
765
+ });
766
+ }
767
+ else if (typeof addableValue === 'string') {
768
+ runFinish({
769
+ text: addableValue,
770
+ value: addableValue,
771
+ });
772
+ }
773
+ else {
774
+ runFinish(addableValue);
775
+ }
776
+ return;
777
+ };
778
+ main.appendChild(addable);
779
+ searchReturn.addable = {
780
+ main: addable,
781
+ svg: plus,
782
+ path: plusPath,
783
+ };
784
+ }
785
+ return searchReturn;
786
+ }
787
+ searchFocus(trigger) {
788
+ if (!trigger) {
789
+ this.settings.triggerFocus = false;
790
+ }
791
+ this.content.search.input.focus();
792
+ this.settings.triggerFocus = true;
793
+ }
794
+ getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
795
+ let query = '.' + this.classes.option;
796
+ if (notPlaceholder) {
797
+ query += ':not(.' + this.classes.placeholder + ')';
798
+ }
799
+ if (notDisabled) {
800
+ query += ':not(.' + this.classes.disabled + ')';
801
+ }
802
+ if (notHidden) {
803
+ query += ':not(.' + this.classes.hide + ')';
804
+ }
805
+ return Array.from(this.content.list.querySelectorAll(query));
806
+ }
807
+ highlight(dir) {
808
+ const options = this.getOptions(true, true, true);
809
+ if (options.length === 0) {
810
+ return;
811
+ }
812
+ if (options.length === 1) {
813
+ if (!options[0].classList.contains(this.classes.highlighted)) {
814
+ options[0].classList.add(this.classes.highlighted);
815
+ return;
816
+ }
817
+ }
818
+ for (let i = 0; i < options.length; i++) {
819
+ if (options[i].classList.contains(this.classes.highlighted)) {
820
+ const prevOption = options[i];
821
+ prevOption.classList.remove(this.classes.highlighted);
822
+ const prevParent = prevOption.parentElement;
823
+ if (prevParent && prevParent.classList.contains(this.classes.open)) {
824
+ const optgroupLabel = prevParent.querySelector('.' + this.classes.optgroupLabel);
825
+ if (optgroupLabel) {
826
+ optgroupLabel.click();
827
+ }
828
+ }
829
+ let selectOption = options[dir === 'down' ? (i + 1 < options.length ? i + 1 : 0) : i - 1 >= 0 ? i - 1 : options.length - 1];
830
+ selectOption.classList.add(this.classes.highlighted);
831
+ this.ensureElementInView(this.content.list, selectOption);
832
+ const selectParent = selectOption.parentElement;
833
+ if (selectParent && selectParent.classList.contains(this.classes.close)) {
834
+ const optgroupLabel = selectParent.querySelector('.' + this.classes.optgroupLabel);
835
+ if (optgroupLabel) {
836
+ optgroupLabel.click();
837
+ }
838
+ }
839
+ return;
840
+ }
841
+ }
842
+ options[dir === 'down' ? 0 : options.length - 1].classList.add(this.classes.highlighted);
843
+ this.ensureElementInView(this.content.list, options[dir === 'down' ? 0 : options.length - 1]);
844
+ }
845
+ listDiv() {
846
+ const options = document.createElement('div');
847
+ options.classList.add(this.classes.list);
848
+ options.setAttribute('role', 'listbox');
849
+ return options;
850
+ }
851
+ renderError(error) {
852
+ this.content.list.innerHTML = '';
853
+ const errorDiv = document.createElement('div');
854
+ errorDiv.classList.add(this.classes.error);
855
+ errorDiv.textContent = error;
856
+ this.content.list.appendChild(errorDiv);
857
+ }
858
+ renderSearching() {
859
+ this.content.list.innerHTML = '';
860
+ const searchingDiv = document.createElement('div');
861
+ searchingDiv.classList.add(this.classes.searching);
862
+ searchingDiv.textContent = this.settings.searchingText;
863
+ this.content.list.appendChild(searchingDiv);
864
+ }
865
+ renderOptions(data) {
866
+ this.content.list.innerHTML = '';
867
+ if (data.length === 0) {
868
+ const noResults = document.createElement('div');
869
+ noResults.classList.add(this.classes.option);
870
+ noResults.classList.add(this.classes.disabled);
871
+ noResults.innerHTML = this.settings.searchText;
872
+ this.content.list.appendChild(noResults);
873
+ return;
874
+ }
875
+ for (const d of data) {
876
+ if (d instanceof Optgroup) {
877
+ const optgroupEl = document.createElement('div');
878
+ optgroupEl.classList.add(this.classes.optgroup);
879
+ const optgroupLabel = document.createElement('div');
880
+ optgroupLabel.classList.add(this.classes.optgroupLabel);
881
+ optgroupEl.appendChild(optgroupLabel);
882
+ const optgroupLabelText = document.createElement('div');
883
+ optgroupLabelText.classList.add(this.classes.optgroupLabelText);
884
+ optgroupLabelText.textContent = d.label;
885
+ optgroupLabel.appendChild(optgroupLabelText);
886
+ const optgroupActions = document.createElement('div');
887
+ optgroupActions.classList.add(this.classes.optgroupActions);
888
+ optgroupLabel.appendChild(optgroupActions);
889
+ if (this.settings.isMultiple && d.selectAll) {
890
+ const selectAll = document.createElement('div');
891
+ selectAll.classList.add(this.classes.optgroupSelectAll);
892
+ let allSelected = true;
893
+ for (const o of d.options) {
894
+ if (!o.selected) {
895
+ allSelected = false;
896
+ break;
897
+ }
898
+ }
899
+ if (allSelected) {
900
+ selectAll.classList.add(this.classes.selected);
901
+ }
902
+ const selectAllText = document.createElement('span');
903
+ selectAllText.textContent = 'Select All';
904
+ selectAll.appendChild(selectAllText);
905
+ const selectAllSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
906
+ selectAllSvg.setAttribute('viewBox', '0 0 100 100');
907
+ selectAll.appendChild(selectAllSvg);
908
+ const selectAllBox = document.createElementNS('http://www.w3.org/2000/svg', 'path');
909
+ selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox);
910
+ selectAllSvg.appendChild(selectAllBox);
911
+ const selectAllCheck = document.createElementNS('http://www.w3.org/2000/svg', 'path');
912
+ selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck);
913
+ selectAllSvg.appendChild(selectAllCheck);
914
+ selectAll.addEventListener('click', (e) => {
915
+ e.preventDefault();
916
+ e.stopPropagation();
917
+ const currentSelected = this.store.getSelected();
918
+ if (allSelected) {
919
+ const newSelected = currentSelected.filter((s) => {
920
+ for (const o of d.options) {
921
+ if (s === o.value) {
922
+ return false;
923
+ }
924
+ }
925
+ return true;
926
+ });
927
+ this.callbacks.setSelected(newSelected);
928
+ return;
929
+ }
930
+ else {
931
+ const newSelected = currentSelected.concat(d.options.map((o) => o.value));
932
+ this.callbacks.setSelected(newSelected);
933
+ }
934
+ });
935
+ optgroupActions.appendChild(selectAll);
936
+ }
937
+ if (d.closable !== 'off') {
938
+ const optgroupClosable = document.createElement('div');
939
+ optgroupClosable.classList.add(this.classes.optgroupClosable);
940
+ const optgroupClosableSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
941
+ optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100');
942
+ optgroupClosableSvg.classList.add(this.classes.arrow);
943
+ optgroupClosable.appendChild(optgroupClosableSvg);
944
+ const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path');
945
+ optgroupClosableArrow.setAttribute('d', this.classes.arrow);
946
+ optgroupClosableSvg.appendChild(optgroupClosableArrow);
947
+ if (d.closable === 'open') {
948
+ optgroupEl.classList.add(this.classes.open);
949
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
950
+ }
951
+ else if (d.closable === 'close') {
952
+ optgroupEl.classList.add(this.classes.close);
953
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
954
+ }
955
+ optgroupLabel.addEventListener('click', (e) => {
956
+ e.preventDefault();
957
+ e.stopPropagation();
958
+ if (optgroupEl.classList.contains(this.classes.close)) {
959
+ optgroupEl.classList.remove(this.classes.close);
960
+ optgroupEl.classList.add(this.classes.open);
961
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
962
+ }
963
+ else {
964
+ optgroupEl.classList.remove(this.classes.open);
965
+ optgroupEl.classList.add(this.classes.close);
966
+ optgroupClosableArrow.setAttribute('d', this.classes.arrowClose);
967
+ }
968
+ });
969
+ optgroupActions.appendChild(optgroupClosable);
970
+ }
971
+ optgroupEl.appendChild(optgroupLabel);
972
+ for (const o of d.options) {
973
+ optgroupEl.appendChild(this.option(o));
974
+ }
975
+ this.content.list.appendChild(optgroupEl);
976
+ }
977
+ if (d instanceof Option) {
978
+ this.content.list.appendChild(this.option(d));
979
+ }
980
+ }
981
+ }
982
+ option(option) {
983
+ if (option.placeholder) {
984
+ const placeholder = document.createElement('div');
985
+ placeholder.classList.add(this.classes.option);
986
+ placeholder.classList.add(this.classes.hide);
987
+ return placeholder;
988
+ }
989
+ const optionEl = document.createElement('div');
990
+ optionEl.dataset.id = option.id;
991
+ optionEl.classList.add(this.classes.option);
992
+ optionEl.setAttribute('role', 'option');
993
+ if (option.class) {
994
+ option.class.split(' ').forEach((dataClass) => {
995
+ optionEl.classList.add(dataClass);
996
+ });
997
+ }
998
+ if (option.style) {
999
+ optionEl.style.cssText = option.style;
1000
+ }
1001
+ if (this.settings.searchHighlight && this.content.search.input.value.trim() !== '') {
1002
+ const textOrHtml = option.html !== '' ? option.html : option.text;
1003
+ optionEl.innerHTML = this.highlightText(textOrHtml, this.content.search.input.value, this.classes.searchHighlighter);
1004
+ }
1005
+ else if (option.html !== '') {
1006
+ optionEl.innerHTML = option.html;
1007
+ }
1008
+ else {
1009
+ optionEl.textContent = option.text;
1010
+ }
1011
+ if (this.settings.showOptionTooltips && optionEl.textContent) {
1012
+ optionEl.setAttribute('title', optionEl.textContent);
1013
+ }
1014
+ if ((option.selected && !this.settings.allowDeselect) || (option.disabled && !this.settings.allowDeselect)) {
1015
+ optionEl.classList.add(this.classes.disabled);
1016
+ }
1017
+ if (option.selected && this.settings.hideSelected) {
1018
+ optionEl.classList.add(this.classes.hide);
1019
+ }
1020
+ if (option.selected) {
1021
+ optionEl.classList.add(this.classes.selected);
1022
+ }
1023
+ else {
1024
+ optionEl.classList.remove(this.classes.selected);
1025
+ }
1026
+ optionEl.addEventListener('click', (e) => {
1027
+ e.preventDefault();
1028
+ e.stopPropagation();
1029
+ const selectedOptions = this.store.getSelected();
1030
+ const element = e.currentTarget;
1031
+ const elementID = String(element.dataset.id);
1032
+ if (option.disabled || (option.selected && !this.settings.allowDeselect)) {
1033
+ return;
1034
+ }
1035
+ if (this.settings.isMultiple &&
1036
+ Array.isArray(selectedOptions) &&
1037
+ this.settings.maxSelected <= selectedOptions.length) {
1038
+ return;
1039
+ }
1040
+ let shouldUpdate = false;
1041
+ const before = this.store.getSelectedOptions();
1042
+ let after = [];
1043
+ if (this.settings.isMultiple) {
1044
+ if (option.selected) {
1045
+ after = before.filter((o) => o.id !== elementID);
1046
+ }
1047
+ else {
1048
+ after = before.concat(option);
1049
+ }
1050
+ }
1051
+ if (!this.settings.isMultiple) {
1052
+ if (option.selected) {
1053
+ after = [];
1054
+ }
1055
+ else {
1056
+ after = [option];
1057
+ }
1058
+ }
1059
+ if (!this.callbacks.beforeChange) {
1060
+ shouldUpdate = true;
1061
+ }
1062
+ if (this.callbacks.beforeChange) {
1063
+ if (this.callbacks.beforeChange(after, before) === false) {
1064
+ shouldUpdate = false;
1065
+ }
1066
+ else {
1067
+ shouldUpdate = true;
1068
+ }
1069
+ }
1070
+ if (shouldUpdate) {
1071
+ if (!this.store.getOptionByID(elementID)) {
1072
+ this.callbacks.addOption(option);
1073
+ }
1074
+ this.callbacks.setSelected(after.map((o) => o.value));
1075
+ if (this.settings.closeOnSelect) {
1076
+ this.callbacks.close();
1077
+ }
1078
+ if (this.callbacks.afterChange) {
1079
+ this.callbacks.afterChange(after);
1080
+ }
1081
+ }
1082
+ });
1083
+ return optionEl;
1084
+ }
1085
+ destroy() {
1086
+ this.main.main.remove();
1087
+ this.content.main.remove();
1088
+ }
1089
+ highlightText(str, search, className) {
1090
+ let completedString = str;
1091
+ const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1092
+ if (!str.match(regex)) {
1093
+ return str;
1094
+ }
1095
+ const matchStartPosition = str.match(regex).index;
1096
+ const matchEndPosition = matchStartPosition + str.match(regex)[0].toString().length;
1097
+ const originalTextFoundByRegex = str.substring(matchStartPosition, matchEndPosition);
1098
+ completedString = completedString.replace(regex, `<mark class="${className}">${originalTextFoundByRegex}</mark>`);
1099
+ return completedString;
1100
+ }
1101
+ moveContentAbove() {
1102
+ let mainHeight = this.main.main.offsetHeight;
1103
+ const contentHeight = this.content.main.offsetHeight;
1104
+ const height = mainHeight + contentHeight - 1;
1105
+ this.content.main.style.margin = '-' + height + 'px 0px 0px 0px';
1106
+ this.content.main.style.transformOrigin = 'center bottom';
1107
+ this.main.main.classList.remove(this.classes.openBelow);
1108
+ this.main.main.classList.add(this.classes.openAbove);
1109
+ this.content.main.classList.remove(this.classes.openBelow);
1110
+ this.content.main.classList.add(this.classes.openAbove);
1111
+ }
1112
+ moveContentBelow() {
1113
+ this.content.main.style.margin = '-1px 0px 0px 0px';
1114
+ this.content.main.style.transformOrigin = 'center top';
1115
+ this.main.main.classList.remove(this.classes.openAbove);
1116
+ this.main.main.classList.add(this.classes.openBelow);
1117
+ this.content.main.classList.remove(this.classes.openAbove);
1118
+ this.content.main.classList.add(this.classes.openBelow);
1119
+ }
1120
+ ensureElementInView(container, element) {
1121
+ const cTop = container.scrollTop + container.offsetTop;
1122
+ const cBottom = cTop + container.clientHeight;
1123
+ const eTop = element.offsetTop;
1124
+ const eBottom = eTop + element.clientHeight;
1125
+ if (eTop < cTop) {
1126
+ container.scrollTop -= cTop - eTop;
1127
+ }
1128
+ else if (eBottom > cBottom) {
1129
+ container.scrollTop += eBottom - cBottom;
1130
+ }
1131
+ }
1132
+ putContent(el, isOpen) {
1133
+ const height = el.offsetHeight;
1134
+ const rect = el.getBoundingClientRect();
1135
+ const elemTop = isOpen ? rect.top : rect.top - height;
1136
+ const elemBottom = isOpen ? rect.bottom : rect.bottom + height;
1137
+ if (elemTop <= 0) {
1138
+ return 'down';
1139
+ }
1140
+ if (elemBottom >= window.innerHeight) {
1141
+ return 'up';
1142
+ }
1143
+ return 'down';
1144
+ }
1145
+ }
1146
+
1147
+ class Select {
1148
+ constructor(select) {
1149
+ this.listen = false;
1150
+ this.observer = null;
1151
+ this.select = select;
1152
+ }
1153
+ enable() {
1154
+ this.disconnectObserver();
1155
+ this.select.disabled = false;
1156
+ this.connectObserver();
1157
+ }
1158
+ disable() {
1159
+ this.disconnectObserver();
1160
+ this.select.disabled = true;
1161
+ this.connectObserver();
1162
+ }
1163
+ hideUI() {
1164
+ this.select.tabIndex = -1;
1165
+ this.select.style.display = 'none';
1166
+ this.select.setAttribute('aria-hidden', 'true');
1167
+ }
1168
+ showUI() {
1169
+ this.select.removeAttribute('tabindex');
1170
+ this.select.style.display = '';
1171
+ this.select.removeAttribute('aria-hidden');
1172
+ }
1173
+ changeListen(on) {
1174
+ this.listen = on;
1175
+ if (this.listen) {
1176
+ this.connectObserver();
1177
+ }
1178
+ else {
1179
+ this.disconnectObserver();
1180
+ }
1181
+ }
1182
+ addSelectChangeListener(func) {
1183
+ this.onSelectChange = func;
1184
+ this.addObserver();
1185
+ this.connectObserver();
1186
+ this.changeListen(true);
1187
+ }
1188
+ removeSelectChangeListener() {
1189
+ this.changeListen(false);
1190
+ this.onSelectChange = undefined;
1191
+ }
1192
+ addValueChangeListener(func) {
1193
+ this.onValueChange = func;
1194
+ this.select.addEventListener('change', this.valueChange.bind(this));
1195
+ }
1196
+ removeValueChangeListener() {
1197
+ this.onValueChange = undefined;
1198
+ this.select.removeEventListener('change', this.valueChange.bind(this));
1199
+ }
1200
+ valueChange(ev) {
1201
+ if (this.onValueChange) {
1202
+ this.onValueChange(this.getSelectedValues());
1203
+ }
1204
+ }
1205
+ observeWrapper(mutations) {
1206
+ if (this.onSelectChange) {
1207
+ this.changeListen(false);
1208
+ this.onSelectChange(this.getData());
1209
+ this.changeListen(true);
1210
+ }
1211
+ }
1212
+ addObserver() {
1213
+ if (this.observer) {
1214
+ this.disconnectObserver();
1215
+ this.observer = null;
1216
+ }
1217
+ this.observer = new MutationObserver(this.observeWrapper.bind(this));
1218
+ }
1219
+ connectObserver() {
1220
+ if (this.observer) {
1221
+ this.observer.observe(this.select, {
1222
+ childList: true,
1223
+ });
1224
+ }
1225
+ }
1226
+ disconnectObserver() {
1227
+ if (this.observer) {
1228
+ this.observer.disconnect();
1229
+ }
1230
+ }
1231
+ getData() {
1232
+ let data = [];
1233
+ const nodes = this.select.childNodes;
1234
+ for (const n of nodes) {
1235
+ if (n.nodeName === 'OPTGROUP') {
1236
+ data.push(this.getDataFromOptgroup(n));
1237
+ }
1238
+ if (n.nodeName === 'OPTION') {
1239
+ data.push(this.getDataFromOption(n));
1240
+ }
1241
+ }
1242
+ return data;
1243
+ }
1244
+ getDataFromOptgroup(optgroup) {
1245
+ let data = {
1246
+ id: (optgroup.dataset ? optgroup.dataset.id : false) || '',
1247
+ label: optgroup.label,
1248
+ selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1249
+ closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
1250
+ options: [],
1251
+ };
1252
+ const options = optgroup.childNodes;
1253
+ for (const o of options) {
1254
+ if (o.nodeName === 'OPTION') {
1255
+ data.options.push(this.getDataFromOption(o));
1256
+ }
1257
+ }
1258
+ return data;
1259
+ }
1260
+ getDataFromOption(option) {
1261
+ return {
1262
+ id: (option.dataset ? option.dataset.id : false) || '',
1263
+ value: option.value,
1264
+ text: option.text,
1265
+ html: option.innerHTML,
1266
+ selected: option.selected,
1267
+ display: option.style.display === 'none' ? false : true,
1268
+ disabled: option.disabled,
1269
+ mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
1270
+ placeholder: option.dataset.placeholder === 'true',
1271
+ class: option.className,
1272
+ style: option.style.cssText,
1273
+ data: option.dataset,
1274
+ };
1275
+ }
1276
+ getSelectedValues() {
1277
+ let values = [];
1278
+ const options = this.select.childNodes;
1279
+ for (const o of options) {
1280
+ if (o.nodeName === 'OPTGROUP') {
1281
+ const optgroupOptions = o.childNodes;
1282
+ for (const oo of optgroupOptions) {
1283
+ if (oo.nodeName === 'OPTION') {
1284
+ const option = oo;
1285
+ if (option.selected) {
1286
+ values.push(option.value);
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+ if (o.nodeName === 'OPTION') {
1292
+ const option = o;
1293
+ if (option.selected) {
1294
+ values.push(option.value);
1295
+ }
1296
+ }
1297
+ }
1298
+ return values;
1299
+ }
1300
+ setSelected(value) {
1301
+ const options = this.select.childNodes;
1302
+ for (const o of options) {
1303
+ if (o.nodeName === 'OPTGROUP') {
1304
+ const optgroup = o;
1305
+ const optgroupOptions = optgroup.childNodes;
1306
+ for (const oo of optgroupOptions) {
1307
+ if (oo.nodeName === 'OPTION') {
1308
+ const option = oo;
1309
+ option.selected = value.includes(option.value);
1310
+ }
1311
+ }
1312
+ }
1313
+ if (o.nodeName === 'OPTION') {
1314
+ const option = o;
1315
+ option.selected = value.includes(option.value);
1316
+ }
1317
+ }
1318
+ }
1319
+ updateSelect(id, style, classes) {
1320
+ this.changeListen(false);
1321
+ if (id) {
1322
+ this.select.id = id;
1323
+ }
1324
+ if (style) {
1325
+ this.select.style.cssText = style;
1326
+ }
1327
+ if (classes) {
1328
+ this.select.className = '';
1329
+ classes.forEach((c) => {
1330
+ if (c.trim() !== '') {
1331
+ this.select.classList.add(c.trim());
1332
+ }
1333
+ });
1334
+ }
1335
+ this.changeListen(true);
1336
+ }
1337
+ updateOptions(data) {
1338
+ this.changeListen(false);
1339
+ this.select.innerHTML = '';
1340
+ for (const d of data) {
1341
+ if (d instanceof Optgroup) {
1342
+ this.select.appendChild(this.createOptgroup(d));
1343
+ }
1344
+ if (d instanceof Option) {
1345
+ this.select.appendChild(this.createOption(d));
1346
+ }
1347
+ }
1348
+ this.changeListen(true);
1349
+ }
1350
+ createOptgroup(optgroup) {
1351
+ const optgroupEl = document.createElement('optgroup');
1352
+ optgroupEl.id = optgroup.id;
1353
+ optgroupEl.label = optgroup.label;
1354
+ if (optgroup.selectAll) {
1355
+ optgroupEl.dataset.selectAll = 'true';
1356
+ }
1357
+ if (optgroup.closable !== 'off') {
1358
+ optgroupEl.dataset.closable = optgroup.closable;
1359
+ }
1360
+ if (optgroup.options) {
1361
+ for (const o of optgroup.options) {
1362
+ optgroupEl.appendChild(this.createOption(o));
1363
+ }
1364
+ }
1365
+ return optgroupEl;
1366
+ }
1367
+ createOption(info) {
1368
+ const optionEl = document.createElement('option');
1369
+ optionEl.value = info.value !== '' ? info.value : info.text;
1370
+ optionEl.innerHTML = info.html || info.text;
1371
+ if (info.selected) {
1372
+ optionEl.selected = info.selected;
1373
+ }
1374
+ if (info.disabled) {
1375
+ optionEl.disabled = true;
1376
+ }
1377
+ if (info.display === false) {
1378
+ optionEl.style.display = 'none';
1379
+ }
1380
+ if (info.placeholder) {
1381
+ optionEl.setAttribute('data-placeholder', 'true');
1382
+ }
1383
+ if (info.mandatory) {
1384
+ optionEl.setAttribute('data-mandatory', 'true');
1385
+ }
1386
+ if (info.class) {
1387
+ info.class.split(' ').forEach((optionClass) => {
1388
+ optionEl.classList.add(optionClass);
1389
+ });
1390
+ }
1391
+ if (info.data && typeof info.data === 'object') {
1392
+ Object.keys(info.data).forEach((key) => {
1393
+ optionEl.setAttribute('data-' + kebabCase(key), info.data[key]);
1394
+ });
1395
+ }
1396
+ return optionEl;
1397
+ }
1398
+ destroy() {
1399
+ this.changeListen(false);
1400
+ this.disconnectObserver();
1401
+ this.removeSelectChangeListener();
1402
+ this.removeValueChangeListener();
1403
+ this.showUI();
1404
+ }
1405
+ }
1406
+
1407
+ class Settings {
1408
+ constructor(settings) {
1409
+ this.id = '';
1410
+ this.style = '';
1411
+ this.class = [];
1412
+ this.isMultiple = false;
1413
+ this.isOpen = false;
1414
+ this.triggerFocus = true;
1415
+ this.intervalMove = null;
1416
+ if (!settings) {
1417
+ settings = {};
1418
+ }
1419
+ this.id = 'ss-' + generateID();
1420
+ this.style = settings.style || '';
1421
+ this.class = settings.class || [];
1422
+ this.isEnabled = settings.isEnabled !== undefined ? settings.isEnabled : true;
1423
+ this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
1424
+ this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
1425
+ this.searchPlaceholder = settings.searchPlaceholder || 'Search';
1426
+ this.searchText = settings.searchText || 'No Results';
1427
+ this.searchingText = settings.searchingText || 'Searching...';
1428
+ this.searchHighlight = settings.searchHighlight !== undefined ? settings.searchHighlight : false;
1429
+ this.closeOnSelect = settings.closeOnSelect !== undefined ? settings.closeOnSelect : true;
1430
+ this.contentLocation = settings.contentLocation || document.body;
1431
+ this.contentPosition = settings.contentPosition || 'absolute';
1432
+ this.openPosition = settings.openPosition || 'auto';
1433
+ this.placeholderText = settings.placeholderText || 'Select Value';
1434
+ this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false;
1435
+ this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false;
1436
+ this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false;
1437
+ this.minSelected = settings.minSelected || 0;
1438
+ this.maxSelected = settings.maxSelected || 1000;
1439
+ this.timeoutDelay = settings.timeoutDelay || 200;
1440
+ }
1441
+ }
1442
+
1443
+ class SlimSelect {
1444
+ constructor(config) {
1445
+ this.events = {
1446
+ search: undefined,
1447
+ searchFilter: (opt, search) => {
1448
+ return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1;
1449
+ },
1450
+ addable: undefined,
1451
+ beforeChange: undefined,
1452
+ afterChange: undefined,
1453
+ beforeOpen: undefined,
1454
+ afterOpen: undefined,
1455
+ beforeClose: undefined,
1456
+ afterClose: undefined,
1457
+ };
1458
+ this.windowResize = debounce(() => {
1459
+ if (!this.settings.isOpen) {
1460
+ return;
1461
+ }
1462
+ this.render.moveContent();
1463
+ });
1464
+ this.windowScroll = debounce(() => {
1465
+ if (!this.settings.isOpen) {
1466
+ return;
1467
+ }
1468
+ if (this.settings.openPosition === 'down') {
1469
+ this.render.moveContentBelow();
1470
+ return;
1471
+ }
1472
+ else if (this.settings.openPosition === 'up') {
1473
+ this.render.moveContentAbove();
1474
+ return;
1475
+ }
1476
+ if (this.settings.contentPosition === 'relative') {
1477
+ this.render.moveContentBelow();
1478
+ }
1479
+ else if (this.render.putContent(this.render.content.main, this.settings.isOpen) === 'up') {
1480
+ this.render.moveContentAbove();
1481
+ }
1482
+ else {
1483
+ this.render.moveContentBelow();
1484
+ }
1485
+ });
1486
+ this.documentClick = (e) => {
1487
+ if (!this.settings.isOpen) {
1488
+ return;
1489
+ }
1490
+ if (e.target && !hasClassInTree(e.target, this.settings.id)) {
1491
+ this.close();
1492
+ }
1493
+ };
1494
+ this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1495
+ if (!this.selectEl) {
1496
+ if (config.events && config.events.error) {
1497
+ config.events.error(new Error('Could not find select element'));
1498
+ }
1499
+ return;
1500
+ }
1501
+ if (this.selectEl.tagName !== 'SELECT') {
1502
+ if (config.events && config.events.error) {
1503
+ config.events.error(new Error('Element isnt of type select'));
1504
+ }
1505
+ return;
1506
+ }
1507
+ if (this.selectEl.dataset.ssid) {
1508
+ this.destroy();
1509
+ }
1510
+ this.settings = new Settings(config.settings);
1511
+ for (const key in config.events) {
1512
+ if (config.events.hasOwnProperty(key)) {
1513
+ this.events[key] = config.events[key];
1514
+ }
1515
+ }
1516
+ this.settings.isMultiple = this.selectEl.multiple;
1517
+ this.settings.style = this.selectEl.style.cssText;
1518
+ this.settings.class = this.selectEl.className.split(' ');
1519
+ this.select = new Select(this.selectEl);
1520
+ this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1521
+ this.select.hideUI();
1522
+ this.select.addSelectChangeListener((data) => {
1523
+ this.setData(data);
1524
+ });
1525
+ this.select.addValueChangeListener((values) => {
1526
+ this.setSelected(values);
1527
+ });
1528
+ this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', config.data ? config.data : this.select.getData());
1529
+ if (config.data) {
1530
+ this.select.updateOptions(this.store.getData());
1531
+ }
1532
+ const callbacks = {
1533
+ open: this.open.bind(this),
1534
+ close: this.close.bind(this),
1535
+ addable: this.events.addable ? this.events.addable : undefined,
1536
+ setSelected: this.setSelected.bind(this),
1537
+ addOption: this.addOption.bind(this),
1538
+ search: this.search.bind(this),
1539
+ beforeChange: this.events.beforeChange,
1540
+ afterChange: this.events.afterChange,
1541
+ };
1542
+ this.render = new Render(this.settings, this.store, callbacks);
1543
+ this.render.renderValues();
1544
+ this.render.renderOptions(this.store.getData());
1545
+ if (this.selectEl.parentNode) {
1546
+ this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
1547
+ }
1548
+ document.addEventListener('click', this.documentClick);
1549
+ window.addEventListener('resize', this.windowResize, false);
1550
+ if (this.settings.openPosition === 'auto') {
1551
+ window.addEventListener('scroll', this.windowScroll, false);
1552
+ }
1553
+ if (!this.settings.isEnabled) {
1554
+ this.disable();
1555
+ }
1556
+ if (this.settings.alwaysOpen) {
1557
+ this.open();
1558
+ }
1559
+ this.selectEl.slim = this;
1560
+ }
1561
+ enable() {
1562
+ this.settings.isEnabled = true;
1563
+ this.select.enable();
1564
+ this.render.enable();
1565
+ }
1566
+ disable() {
1567
+ this.settings.isEnabled = false;
1568
+ this.select.disable();
1569
+ this.render.disable();
1570
+ }
1571
+ getData() {
1572
+ return this.store.getData();
1573
+ }
1574
+ setData(data) {
1575
+ const err = this.store.validateDataArray(data);
1576
+ if (err) {
1577
+ if (this.events.error) {
1578
+ this.events.error(err);
1579
+ }
1580
+ return;
1581
+ }
1582
+ this.store.setData(data);
1583
+ const dataClean = this.store.getData();
1584
+ this.select.updateOptions(dataClean);
1585
+ this.render.renderValues();
1586
+ this.render.renderOptions(dataClean);
1587
+ }
1588
+ getSelected() {
1589
+ return this.store.getSelected();
1590
+ }
1591
+ setSelected(value) {
1592
+ this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1593
+ const data = this.store.getData();
1594
+ this.select.updateOptions(data);
1595
+ this.render.renderValues();
1596
+ this.render.renderOptions(data);
1597
+ }
1598
+ addOption(option) {
1599
+ this.store.addOption(option);
1600
+ const data = this.store.getData();
1601
+ this.select.updateOptions(data);
1602
+ this.render.renderValues();
1603
+ this.render.renderOptions(data);
1604
+ }
1605
+ open() {
1606
+ if (!this.settings.isEnabled || this.settings.isOpen) {
1607
+ return;
1608
+ }
1609
+ if (this.events.beforeOpen) {
1610
+ this.events.beforeOpen();
1611
+ }
1612
+ this.render.open();
1613
+ if (this.settings.showSearch) {
1614
+ this.render.searchFocus(false);
1615
+ }
1616
+ setTimeout(() => {
1617
+ if (this.events.afterOpen) {
1618
+ this.events.afterOpen();
1619
+ }
1620
+ this.settings.isOpen = true;
1621
+ }, this.settings.timeoutDelay);
1622
+ if (this.settings.intervalMove) {
1623
+ clearInterval(this.settings.intervalMove);
1624
+ }
1625
+ this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1626
+ }
1627
+ close() {
1628
+ if (!this.settings.isOpen || this.settings.alwaysOpen) {
1629
+ return;
1630
+ }
1631
+ if (this.events.beforeClose) {
1632
+ this.events.beforeClose();
1633
+ }
1634
+ this.render.close();
1635
+ this.search('');
1636
+ this.render.mainFocus(false);
1637
+ setTimeout(() => {
1638
+ if (this.events.afterClose) {
1639
+ this.events.afterClose();
1640
+ }
1641
+ this.settings.isOpen = false;
1642
+ }, this.settings.timeoutDelay);
1643
+ if (this.settings.intervalMove) {
1644
+ clearInterval(this.settings.intervalMove);
1645
+ }
1646
+ }
1647
+ search(value) {
1648
+ if (this.render.content.search.input.value !== value) {
1649
+ this.render.content.search.input.value = value;
1650
+ }
1651
+ if (!this.events.search) {
1652
+ this.render.renderOptions(value === '' ? this.store.getData() : this.store.search(value, this.events.searchFilter));
1653
+ return;
1654
+ }
1655
+ this.render.renderSearching();
1656
+ const searchResp = this.events.search(value, this.store.getSelectedOptions());
1657
+ if (searchResp instanceof Promise) {
1658
+ searchResp
1659
+ .then((data) => {
1660
+ this.render.renderOptions(this.store.partialToFullData(data));
1661
+ })
1662
+ .catch((err) => {
1663
+ this.render.renderError(typeof err === 'string' ? err : err.message);
1664
+ });
1665
+ return;
1666
+ }
1667
+ else if (Array.isArray(searchResp)) {
1668
+ this.render.renderOptions(this.store.partialToFullData(searchResp));
1669
+ }
1670
+ else {
1671
+ this.render.renderError('Search event must return a promise or an array of data');
1672
+ }
1673
+ }
1674
+ destroy() {
1675
+ document.removeEventListener('click', this.documentClick);
1676
+ window.removeEventListener('resize', this.windowResize, false);
1677
+ if (this.settings.openPosition === 'auto') {
1678
+ window.removeEventListener('scroll', this.windowScroll, false);
1679
+ }
1680
+ this.store.setData([]);
1681
+ this.render.destroy();
1682
+ this.select.destroy();
1683
+ }
1684
+ }
1685
+
1686
+ var script = defineComponent({
1687
+ name: 'SlimSelect',
1688
+ props: {
1689
+ data: {
1690
+ type: Array,
1691
+ },
1692
+ settings: {
1693
+ type: Object,
1694
+ },
1695
+ events: {
1696
+ type: Object,
1697
+ },
1698
+ },
1699
+ data() {
1700
+ return {
1701
+ slim: null,
1702
+ };
1703
+ },
1704
+ mounted() {
1705
+ let config = {
1706
+ select: this.$refs.slim,
1707
+ };
1708
+ if (this.data) {
1709
+ config.data = this.data;
1710
+ }
1711
+ if (this.settings) {
1712
+ config.settings = this.settings;
1713
+ }
1714
+ if (this.events) {
1715
+ config.events = this.events;
1716
+ }
1717
+ this.slim = new SlimSelect(config);
1718
+ },
1719
+ beforeUnmount() {
1720
+ if (this.slim) {
1721
+ this.slim.destroy();
1722
+ }
1723
+ },
1724
+ watch: {
1725
+ data: {
1726
+ handler: function (newData) {
1727
+ if (this.slim) {
1728
+ this.slim.setData(newData);
1729
+ }
1730
+ },
1731
+ deep: true,
1732
+ },
1733
+ },
1734
+ methods: {
1735
+ getSlimSelect() {
1736
+ return this.slim;
1737
+ },
1738
+ },
1739
+ });
1740
+
1741
+ const _hoisted_1 = { ref: "slim" };
1742
+
1743
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
1744
+ return (openBlock(), createElementBlock("select", _hoisted_1, [
1745
+ renderSlot(_ctx.$slots, "default")
1746
+ ], 512 /* NEED_PATCH */))
1747
+ }
1748
+
1749
+ script.render = render;
1750
+ script.__file = "slimselect.vue";
1751
+
1752
+ export { script as default };