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