slim-select 2.4.5 → 2.5.1

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