slim-select 2.4.5 → 2.5.1

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