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