slim-select 2.8.2 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +1 -0
- package/.prettierrc +4 -3
- package/README.md +2 -0
- package/dist/classes.d.ts +43 -0
- package/dist/helpers.d.ts +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/render.d.ts +4 -44
- package/dist/select.d.ts +4 -2
- package/dist/settings.d.ts +2 -1
- package/dist/slimselect.cjs.js +248 -120
- package/dist/slimselect.css +1 -1
- package/dist/slimselect.css.map +1 -1
- package/dist/slimselect.es.js +248 -120
- package/dist/slimselect.global.js +248 -120
- package/dist/slimselect.js +248 -120
- package/dist/slimselect.min.js +1 -1
- package/dist/slimselect.umd.js +248 -120
- package/dist/slimselect.umd.min.js +1 -1
- package/dist/store.d.ts +4 -2
- package/index.html +1 -4
- package/jest.config.js +6 -0
- package/package.json +30 -39
- package/src/slim-select/classes.test.ts +72 -0
- package/src/slim-select/classes.ts +109 -0
- package/src/slim-select/helpers.test.ts +160 -0
- package/src/slim-select/helpers.ts +3 -12
- package/src/slim-select/index.test.ts +109 -16
- package/src/slim-select/index.ts +41 -12
- package/src/slim-select/render.test.ts +1169 -18
- package/src/slim-select/render.ts +75 -96
- package/src/slim-select/rollup.config.mjs +28 -28
- package/src/slim-select/select.test.ts +306 -156
- package/src/slim-select/select.ts +69 -20
- package/src/slim-select/settings.test.ts +257 -0
- package/src/slim-select/settings.ts +4 -0
- package/src/slim-select/slimselect.scss +7 -3
- package/src/slim-select/store.test.ts +986 -235
- package/src/slim-select/store.ts +70 -28
- package/src/{vue/slimselect.vue → slim-select/vue.vue} +19 -17
- package/tsconfig.json +2 -3
- package/src/react/.eslintignore +0 -2
- package/src/react/.eslintrc.cjs +0 -24
- package/src/react/index.html +0 -14
- package/src/react/jestconfig.json +0 -11
- package/src/react/package.json +0 -32
- package/src/react/src/frameworkpage.tsx +0 -133
- package/src/react/src/index.ts +0 -3
- package/src/react/src/slimselect.tsx +0 -148
- package/src/react/tests/slimselect.test.tsx +0 -52
- package/src/react/tsconfig.json +0 -37
- package/src/react/tsconfig.node.json +0 -10
- package/src/react/vite.config.ts +0 -55
- package/src/vue/README.md +0 -48
- package/src/vue/dist/slim-select/helpers.d.ts +0 -5
- package/src/vue/dist/slim-select/index.d.ts +0 -46
- package/src/vue/dist/slim-select/render.d.ts +0 -120
- package/src/vue/dist/slim-select/select.d.ts +0 -28
- package/src/vue/dist/slim-select/settings.d.ts +0 -34
- package/src/vue/dist/slim-select/store.d.ts +0 -80
- package/src/vue/dist/slimselectvue.es.js +0 -1978
- package/src/vue/dist/slimselectvue.global.js +0 -1981
- package/src/vue/dist/slimselectvue.ssr.js +0 -1980
- package/src/vue/dist/vue/hello.d.ts +0 -2
- package/src/vue/dist/vue/slimselect.vue.d.ts +0 -326
- package/src/vue/hello.ts +0 -5
- package/src/vue/package.json +0 -28
- package/src/vue/rollup.config.mjs +0 -44
- package/src/vue/tsconfig.json +0 -14
- /package/{vite.config.ts → vite.config.mts} +0 -0
package/dist/slimselect.es.js
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
class CssClasses {
|
|
2
|
+
constructor(classes) {
|
|
3
|
+
if (!classes) {
|
|
4
|
+
classes = {};
|
|
5
|
+
}
|
|
6
|
+
this.main = classes.main || 'ss-main';
|
|
7
|
+
this.placeholder = classes.placeholder || 'ss-placeholder';
|
|
8
|
+
this.values = classes.values || 'ss-values';
|
|
9
|
+
this.single = classes.single || 'ss-single';
|
|
10
|
+
this.max = classes.max || 'ss-max';
|
|
11
|
+
this.value = classes.value || 'ss-value';
|
|
12
|
+
this.valueText = classes.valueText || 'ss-value-text';
|
|
13
|
+
this.valueDelete = classes.valueDelete || 'ss-value-delete';
|
|
14
|
+
this.valueOut = classes.valueOut || 'ss-value-out';
|
|
15
|
+
this.deselect = classes.deselect || 'ss-deselect';
|
|
16
|
+
this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10';
|
|
17
|
+
this.arrow = classes.arrow || 'ss-arrow';
|
|
18
|
+
this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30';
|
|
19
|
+
this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70';
|
|
20
|
+
this.content = classes.content || 'ss-content';
|
|
21
|
+
this.openAbove = classes.openAbove || 'ss-open-above';
|
|
22
|
+
this.openBelow = classes.openBelow || 'ss-open-below';
|
|
23
|
+
this.search = classes.search || 'ss-search';
|
|
24
|
+
this.searchHighlighter = classes.searchHighlighter || 'ss-search-highlight';
|
|
25
|
+
this.searching = classes.searching || 'ss-searching';
|
|
26
|
+
this.addable = classes.addable || 'ss-addable';
|
|
27
|
+
this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50';
|
|
28
|
+
this.list = classes.list || 'ss-list';
|
|
29
|
+
this.optgroup = classes.optgroup || 'ss-optgroup';
|
|
30
|
+
this.optgroupLabel = classes.optgroupLabel || 'ss-optgroup-label';
|
|
31
|
+
this.optgroupLabelText = classes.optgroupLabelText || 'ss-optgroup-label-text';
|
|
32
|
+
this.optgroupActions = classes.optgroupActions || 'ss-optgroup-actions';
|
|
33
|
+
this.optgroupSelectAll = classes.optgroupSelectAll || 'ss-selectall';
|
|
34
|
+
this.optgroupSelectAllBox = classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50';
|
|
35
|
+
this.optgroupSelectAllCheck = classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10';
|
|
36
|
+
this.optgroupClosable = classes.optgroupClosable || 'ss-closable';
|
|
37
|
+
this.option = classes.option || 'ss-option';
|
|
38
|
+
this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10';
|
|
39
|
+
this.highlighted = classes.highlighted || 'ss-highlighted';
|
|
40
|
+
this.open = classes.open || 'ss-open';
|
|
41
|
+
this.close = classes.close || 'ss-close';
|
|
42
|
+
this.selected = classes.selected || 'ss-selected';
|
|
43
|
+
this.error = classes.error || 'ss-error';
|
|
44
|
+
this.disabled = classes.disabled || 'ss-disabled';
|
|
45
|
+
this.hide = classes.hide || 'ss-hide';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
1
49
|
function generateID() {
|
|
2
50
|
return Math.random().toString(36).substring(2, 10);
|
|
3
51
|
}
|
|
@@ -85,6 +133,7 @@ class Store {
|
|
|
85
133
|
constructor(type, data) {
|
|
86
134
|
this.selectType = 'single';
|
|
87
135
|
this.data = [];
|
|
136
|
+
this.selectedOrder = [];
|
|
88
137
|
this.selectType = type;
|
|
89
138
|
this.setData(data);
|
|
90
139
|
}
|
|
@@ -99,12 +148,18 @@ class Store {
|
|
|
99
148
|
}
|
|
100
149
|
if ('options' in dataObj && dataObj.options) {
|
|
101
150
|
for (let option of dataObj.options) {
|
|
102
|
-
|
|
151
|
+
const validationError = this.validateOption(option);
|
|
152
|
+
if (validationError) {
|
|
153
|
+
return validationError;
|
|
154
|
+
}
|
|
103
155
|
}
|
|
104
156
|
}
|
|
105
157
|
}
|
|
106
158
|
else if (dataObj instanceof Option || 'text' in dataObj) {
|
|
107
|
-
|
|
159
|
+
const validationError = this.validateOption(dataObj);
|
|
160
|
+
if (validationError) {
|
|
161
|
+
return validationError;
|
|
162
|
+
}
|
|
108
163
|
}
|
|
109
164
|
else {
|
|
110
165
|
return new Error('Data object must be a valid optgroup or option');
|
|
@@ -141,7 +196,7 @@ class Store {
|
|
|
141
196
|
setData(data) {
|
|
142
197
|
this.data = this.partialToFullData(data);
|
|
143
198
|
if (this.selectType === 'single') {
|
|
144
|
-
this.setSelectedBy('
|
|
199
|
+
this.setSelectedBy('id', this.getSelected());
|
|
145
200
|
}
|
|
146
201
|
}
|
|
147
202
|
getData() {
|
|
@@ -150,12 +205,19 @@ class Store {
|
|
|
150
205
|
getDataOptions() {
|
|
151
206
|
return this.filter(null, false);
|
|
152
207
|
}
|
|
153
|
-
addOption(option) {
|
|
154
|
-
|
|
208
|
+
addOption(option, addToStart = false) {
|
|
209
|
+
if (addToStart) {
|
|
210
|
+
let data = [new Option(option)];
|
|
211
|
+
this.setData(data.concat(this.getData()));
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
this.setData(this.getData().concat(new Option(option)));
|
|
215
|
+
}
|
|
155
216
|
}
|
|
156
217
|
setSelectedBy(selectedType, selectedValues) {
|
|
157
218
|
let firstOption = null;
|
|
158
219
|
let hasSelected = false;
|
|
220
|
+
const selectedObjects = [];
|
|
159
221
|
for (let dataObj of this.data) {
|
|
160
222
|
if (dataObj instanceof Optgroup) {
|
|
161
223
|
for (let option of dataObj.options) {
|
|
@@ -163,8 +225,11 @@ class Store {
|
|
|
163
225
|
firstOption = option;
|
|
164
226
|
}
|
|
165
227
|
option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
|
|
166
|
-
if (option.selected
|
|
167
|
-
|
|
228
|
+
if (option.selected) {
|
|
229
|
+
selectedObjects.push(option);
|
|
230
|
+
if (this.selectType === 'single') {
|
|
231
|
+
hasSelected = true;
|
|
232
|
+
}
|
|
168
233
|
}
|
|
169
234
|
}
|
|
170
235
|
}
|
|
@@ -173,36 +238,35 @@ class Store {
|
|
|
173
238
|
firstOption = dataObj;
|
|
174
239
|
}
|
|
175
240
|
dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
|
|
176
|
-
if (dataObj.selected
|
|
177
|
-
|
|
241
|
+
if (dataObj.selected) {
|
|
242
|
+
selectedObjects.push(dataObj);
|
|
243
|
+
if (this.selectType === 'single') {
|
|
244
|
+
hasSelected = true;
|
|
245
|
+
}
|
|
178
246
|
}
|
|
179
247
|
}
|
|
180
248
|
}
|
|
181
249
|
if (this.selectType === 'single' && firstOption && !hasSelected) {
|
|
182
250
|
firstOption.selected = true;
|
|
251
|
+
selectedObjects.push(firstOption);
|
|
183
252
|
}
|
|
253
|
+
const selectedIds = selectedValues.map((value) => {
|
|
254
|
+
var _a;
|
|
255
|
+
return ((_a = selectedObjects.find((option) => option[selectedType] === value)) === null || _a === void 0 ? void 0 : _a.id) || '';
|
|
256
|
+
});
|
|
257
|
+
this.selectedOrder = selectedIds;
|
|
184
258
|
}
|
|
185
259
|
getSelected() {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
});
|
|
191
|
-
return selectedValues;
|
|
260
|
+
return this.getSelectedOptions().map((option) => option.id);
|
|
261
|
+
}
|
|
262
|
+
getSelectedValues() {
|
|
263
|
+
return this.getSelectedOptions().map((option) => option.value);
|
|
192
264
|
}
|
|
193
265
|
getSelectedOptions() {
|
|
194
266
|
return this.filter((opt) => {
|
|
195
267
|
return opt.selected;
|
|
196
268
|
}, false);
|
|
197
269
|
}
|
|
198
|
-
getSelectedIDs() {
|
|
199
|
-
let selectedOptions = this.getSelectedOptions();
|
|
200
|
-
let selectedIDs = [];
|
|
201
|
-
selectedOptions.forEach((op) => {
|
|
202
|
-
selectedIDs.push(op.id);
|
|
203
|
-
});
|
|
204
|
-
return selectedIDs;
|
|
205
|
-
}
|
|
206
270
|
getOptgroupByID(id) {
|
|
207
271
|
for (let dataObj of this.data) {
|
|
208
272
|
if (dataObj instanceof Optgroup && dataObj.id === id) {
|
|
@@ -273,54 +337,35 @@ class Store {
|
|
|
273
337
|
});
|
|
274
338
|
return dataSearch;
|
|
275
339
|
}
|
|
340
|
+
selectedOrderOptions(options) {
|
|
341
|
+
const newOrder = [];
|
|
342
|
+
this.selectedOrder.forEach((id) => {
|
|
343
|
+
const option = options.find((opt) => opt.id === id);
|
|
344
|
+
if (option) {
|
|
345
|
+
newOrder.push(option);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
options.forEach((option) => {
|
|
349
|
+
let isIn = false;
|
|
350
|
+
newOrder.forEach((selectedOption) => {
|
|
351
|
+
if (option.id === selectedOption.id) {
|
|
352
|
+
isIn = true;
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
if (!isIn) {
|
|
357
|
+
newOrder.push(option);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
return newOrder;
|
|
361
|
+
}
|
|
276
362
|
}
|
|
277
363
|
|
|
278
364
|
class Render {
|
|
279
|
-
constructor(settings, store, callbacks) {
|
|
280
|
-
this.classes = {
|
|
281
|
-
main: 'ss-main',
|
|
282
|
-
placeholder: 'ss-placeholder',
|
|
283
|
-
values: 'ss-values',
|
|
284
|
-
single: 'ss-single',
|
|
285
|
-
max: 'ss-max',
|
|
286
|
-
value: 'ss-value',
|
|
287
|
-
valueText: 'ss-value-text',
|
|
288
|
-
valueDelete: 'ss-value-delete',
|
|
289
|
-
valueOut: 'ss-value-out',
|
|
290
|
-
deselect: 'ss-deselect',
|
|
291
|
-
deselectPath: 'M10,10 L90,90 M10,90 L90,10',
|
|
292
|
-
arrow: 'ss-arrow',
|
|
293
|
-
arrowClose: 'M10,30 L50,70 L90,30',
|
|
294
|
-
arrowOpen: 'M10,70 L50,30 L90,70',
|
|
295
|
-
content: 'ss-content',
|
|
296
|
-
openAbove: 'ss-open-above',
|
|
297
|
-
openBelow: 'ss-open-below',
|
|
298
|
-
search: 'ss-search',
|
|
299
|
-
searchHighlighter: 'ss-search-highlight',
|
|
300
|
-
searching: 'ss-searching',
|
|
301
|
-
addable: 'ss-addable',
|
|
302
|
-
addablePath: 'M50,10 L50,90 M10,50 L90,50',
|
|
303
|
-
list: 'ss-list',
|
|
304
|
-
optgroup: 'ss-optgroup',
|
|
305
|
-
optgroupLabel: 'ss-optgroup-label',
|
|
306
|
-
optgroupLabelText: 'ss-optgroup-label-text',
|
|
307
|
-
optgroupActions: 'ss-optgroup-actions',
|
|
308
|
-
optgroupSelectAll: 'ss-selectall',
|
|
309
|
-
optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
|
|
310
|
-
optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
|
|
311
|
-
optgroupClosable: 'ss-closable',
|
|
312
|
-
option: 'ss-option',
|
|
313
|
-
optionDelete: 'M10,10 L90,90 M10,90 L90,10',
|
|
314
|
-
highlighted: 'ss-highlighted',
|
|
315
|
-
open: 'ss-open',
|
|
316
|
-
close: 'ss-close',
|
|
317
|
-
selected: 'ss-selected',
|
|
318
|
-
error: 'ss-error',
|
|
319
|
-
disabled: 'ss-disabled',
|
|
320
|
-
hide: 'ss-hide',
|
|
321
|
-
};
|
|
365
|
+
constructor(settings, classes, store, callbacks) {
|
|
322
366
|
this.store = store;
|
|
323
367
|
this.settings = settings;
|
|
368
|
+
this.classes = classes;
|
|
324
369
|
this.callbacks = callbacks;
|
|
325
370
|
this.main = this.mainDiv();
|
|
326
371
|
this.content = this.contentDiv();
|
|
@@ -416,7 +461,7 @@ class Render {
|
|
|
416
461
|
this.callbacks.close();
|
|
417
462
|
return false;
|
|
418
463
|
}
|
|
419
|
-
return
|
|
464
|
+
return true;
|
|
420
465
|
};
|
|
421
466
|
main.onclick = (e) => {
|
|
422
467
|
if (this.settings.disabled) {
|
|
@@ -454,8 +499,8 @@ class Render {
|
|
|
454
499
|
}
|
|
455
500
|
else {
|
|
456
501
|
const firstOption = this.store.getFirstOption();
|
|
457
|
-
const
|
|
458
|
-
this.callbacks.setSelected(
|
|
502
|
+
const id = firstOption ? firstOption.id : '';
|
|
503
|
+
this.callbacks.setSelected(id, false);
|
|
459
504
|
}
|
|
460
505
|
if (this.settings.closeOnSelect) {
|
|
461
506
|
this.callbacks.close();
|
|
@@ -488,12 +533,12 @@ class Render {
|
|
|
488
533
|
deselect: {
|
|
489
534
|
main: deselect,
|
|
490
535
|
svg: deselectSvg,
|
|
491
|
-
path: deselectPath
|
|
536
|
+
path: deselectPath
|
|
492
537
|
},
|
|
493
538
|
arrow: {
|
|
494
539
|
main: arrow,
|
|
495
|
-
path: arrowPath
|
|
496
|
-
}
|
|
540
|
+
path: arrowPath
|
|
541
|
+
}
|
|
497
542
|
};
|
|
498
543
|
}
|
|
499
544
|
mainFocus(eventType) {
|
|
@@ -579,6 +624,9 @@ class Render {
|
|
|
579
624
|
maxValuesMessage.remove();
|
|
580
625
|
}
|
|
581
626
|
}
|
|
627
|
+
if (this.settings.keepOrder) {
|
|
628
|
+
selectedOptions = this.store.selectedOrderOptions(selectedOptions);
|
|
629
|
+
}
|
|
582
630
|
let removeNodes = [];
|
|
583
631
|
for (let i = 0; i < currentNodes.length; i++) {
|
|
584
632
|
const node = currentNodes[i];
|
|
@@ -632,7 +680,7 @@ class Render {
|
|
|
632
680
|
value.dataset.id = option.id;
|
|
633
681
|
const text = document.createElement('div');
|
|
634
682
|
text.classList.add(this.classes.valueText);
|
|
635
|
-
text.
|
|
683
|
+
text.textContent = option.text;
|
|
636
684
|
value.appendChild(text);
|
|
637
685
|
if (!option.mandatory) {
|
|
638
686
|
const deleteDiv = document.createElement('div');
|
|
@@ -655,18 +703,18 @@ class Render {
|
|
|
655
703
|
shouldDelete = this.callbacks.beforeChange(after, before) === true;
|
|
656
704
|
}
|
|
657
705
|
if (shouldDelete) {
|
|
658
|
-
let
|
|
706
|
+
let selectedIds = [];
|
|
659
707
|
for (const o of after) {
|
|
660
708
|
if (o instanceof Optgroup) {
|
|
661
709
|
for (const c of o.options) {
|
|
662
|
-
|
|
710
|
+
selectedIds.push(c.id);
|
|
663
711
|
}
|
|
664
712
|
}
|
|
665
713
|
if (o instanceof Option) {
|
|
666
|
-
|
|
714
|
+
selectedIds.push(o.id);
|
|
667
715
|
}
|
|
668
716
|
}
|
|
669
|
-
this.callbacks.setSelected(
|
|
717
|
+
this.callbacks.setSelected(selectedIds, false);
|
|
670
718
|
if (this.settings.closeOnSelect) {
|
|
671
719
|
this.callbacks.close();
|
|
672
720
|
}
|
|
@@ -696,7 +744,7 @@ class Render {
|
|
|
696
744
|
return {
|
|
697
745
|
main: main,
|
|
698
746
|
search: search,
|
|
699
|
-
list: list
|
|
747
|
+
list: list
|
|
700
748
|
};
|
|
701
749
|
}
|
|
702
750
|
moveContent() {
|
|
@@ -726,7 +774,7 @@ class Render {
|
|
|
726
774
|
main.classList.add(this.classes.search);
|
|
727
775
|
const searchReturn = {
|
|
728
776
|
main,
|
|
729
|
-
input
|
|
777
|
+
input
|
|
730
778
|
};
|
|
731
779
|
if (!this.settings.showSearch) {
|
|
732
780
|
main.classList.add(this.classes.hide);
|
|
@@ -754,9 +802,15 @@ class Render {
|
|
|
754
802
|
case 'Escape':
|
|
755
803
|
this.callbacks.close();
|
|
756
804
|
return false;
|
|
757
|
-
case 'Enter':
|
|
758
805
|
case ' ':
|
|
759
|
-
|
|
806
|
+
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
807
|
+
if (highlighted) {
|
|
808
|
+
highlighted.click();
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
return true;
|
|
812
|
+
case 'Enter':
|
|
813
|
+
if (this.callbacks.addable) {
|
|
760
814
|
addable.click();
|
|
761
815
|
return false;
|
|
762
816
|
}
|
|
@@ -795,12 +849,12 @@ class Render {
|
|
|
795
849
|
let newOption = new Option(oo);
|
|
796
850
|
this.callbacks.addOption(newOption);
|
|
797
851
|
if (this.settings.isMultiple) {
|
|
798
|
-
let
|
|
799
|
-
|
|
800
|
-
this.callbacks.setSelected(
|
|
852
|
+
let ids = this.store.getSelected();
|
|
853
|
+
ids.push(newOption.id);
|
|
854
|
+
this.callbacks.setSelected(ids, true);
|
|
801
855
|
}
|
|
802
856
|
else {
|
|
803
|
-
this.callbacks.setSelected([newOption.
|
|
857
|
+
this.callbacks.setSelected([newOption.id], true);
|
|
804
858
|
}
|
|
805
859
|
this.callbacks.search('');
|
|
806
860
|
if (this.settings.closeOnSelect) {
|
|
@@ -818,9 +872,12 @@ class Render {
|
|
|
818
872
|
if (typeof value === 'string') {
|
|
819
873
|
runFinish({
|
|
820
874
|
text: value,
|
|
821
|
-
value: value
|
|
875
|
+
value: value
|
|
822
876
|
});
|
|
823
877
|
}
|
|
878
|
+
else if (addableValue instanceof Error) {
|
|
879
|
+
this.renderError(addableValue.message);
|
|
880
|
+
}
|
|
824
881
|
else {
|
|
825
882
|
runFinish(value);
|
|
826
883
|
}
|
|
@@ -829,9 +886,12 @@ class Render {
|
|
|
829
886
|
else if (typeof addableValue === 'string') {
|
|
830
887
|
runFinish({
|
|
831
888
|
text: addableValue,
|
|
832
|
-
value: addableValue
|
|
889
|
+
value: addableValue
|
|
833
890
|
});
|
|
834
891
|
}
|
|
892
|
+
else if (addableValue instanceof Error) {
|
|
893
|
+
this.renderError(addableValue.message);
|
|
894
|
+
}
|
|
835
895
|
else {
|
|
836
896
|
runFinish(addableValue);
|
|
837
897
|
}
|
|
@@ -841,7 +901,7 @@ class Render {
|
|
|
841
901
|
searchReturn.addable = {
|
|
842
902
|
main: addable,
|
|
843
903
|
svg: plus,
|
|
844
|
-
path: plusPath
|
|
904
|
+
path: plusPath
|
|
845
905
|
};
|
|
846
906
|
}
|
|
847
907
|
return searchReturn;
|
|
@@ -938,10 +998,26 @@ class Render {
|
|
|
938
998
|
if (data.length === 0) {
|
|
939
999
|
const noResults = document.createElement('div');
|
|
940
1000
|
noResults.classList.add(this.classes.search);
|
|
941
|
-
|
|
1001
|
+
if (this.callbacks.addable) {
|
|
1002
|
+
noResults.innerHTML = this.settings.addableText.replace('{value}', this.content.search.input.value);
|
|
1003
|
+
}
|
|
1004
|
+
else {
|
|
1005
|
+
noResults.innerHTML = this.settings.searchText;
|
|
1006
|
+
}
|
|
942
1007
|
this.content.list.appendChild(noResults);
|
|
943
1008
|
return;
|
|
944
1009
|
}
|
|
1010
|
+
if (this.settings.allowDeselect && !this.settings.isMultiple) {
|
|
1011
|
+
const placeholderOption = this.store.filter((o) => o.placeholder, false);
|
|
1012
|
+
if (!placeholderOption.length) {
|
|
1013
|
+
this.store.addOption(new Option({
|
|
1014
|
+
text: '',
|
|
1015
|
+
value: '',
|
|
1016
|
+
selected: false,
|
|
1017
|
+
placeholder: true
|
|
1018
|
+
}), true);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
945
1021
|
for (const d of data) {
|
|
946
1022
|
if (d instanceof Optgroup) {
|
|
947
1023
|
const optgroupEl = document.createElement('div');
|
|
@@ -988,7 +1064,7 @@ class Render {
|
|
|
988
1064
|
if (allSelected) {
|
|
989
1065
|
const newSelected = currentSelected.filter((s) => {
|
|
990
1066
|
for (const o of d.options) {
|
|
991
|
-
if (s === o.
|
|
1067
|
+
if (s === o.id) {
|
|
992
1068
|
return false;
|
|
993
1069
|
}
|
|
994
1070
|
}
|
|
@@ -998,7 +1074,7 @@ class Render {
|
|
|
998
1074
|
return;
|
|
999
1075
|
}
|
|
1000
1076
|
else {
|
|
1001
|
-
const newSelected = currentSelected.concat(d.options.map((o) => o.
|
|
1077
|
+
const newSelected = currentSelected.concat(d.options.map((o) => o.id));
|
|
1002
1078
|
for (const o of d.options) {
|
|
1003
1079
|
if (!this.store.getOptionByID(o.id)) {
|
|
1004
1080
|
this.callbacks.addOption(o);
|
|
@@ -1155,7 +1231,7 @@ class Render {
|
|
|
1155
1231
|
if (!this.store.getOptionByID(elementID)) {
|
|
1156
1232
|
this.callbacks.addOption(option);
|
|
1157
1233
|
}
|
|
1158
|
-
this.callbacks.setSelected(after.map((o) => o.
|
|
1234
|
+
this.callbacks.setSelected(after.map((o) => o.id), false);
|
|
1159
1235
|
if (this.settings.closeOnSelect) {
|
|
1160
1236
|
this.callbacks.close();
|
|
1161
1237
|
}
|
|
@@ -1172,7 +1248,7 @@ class Render {
|
|
|
1172
1248
|
}
|
|
1173
1249
|
highlightText(str, search, className) {
|
|
1174
1250
|
let completedString = str;
|
|
1175
|
-
const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
|
|
1251
|
+
const regex = new RegExp('(?![^<]*>)(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
|
|
1176
1252
|
if (!str.match(regex)) {
|
|
1177
1253
|
return str;
|
|
1178
1254
|
}
|
|
@@ -1261,7 +1337,7 @@ class Select {
|
|
|
1261
1337
|
this.select = select;
|
|
1262
1338
|
this.valueChange = this.valueChange.bind(this);
|
|
1263
1339
|
this.select.addEventListener('change', this.valueChange, {
|
|
1264
|
-
passive: true
|
|
1340
|
+
passive: true
|
|
1265
1341
|
});
|
|
1266
1342
|
this.observer = new MutationObserver(this.observeCall.bind(this));
|
|
1267
1343
|
this.changeListen(true);
|
|
@@ -1289,7 +1365,7 @@ class Select {
|
|
|
1289
1365
|
this.observer.observe(this.select, {
|
|
1290
1366
|
subtree: true,
|
|
1291
1367
|
childList: true,
|
|
1292
|
-
attributes: true
|
|
1368
|
+
attributes: true
|
|
1293
1369
|
});
|
|
1294
1370
|
}
|
|
1295
1371
|
}
|
|
@@ -1301,7 +1377,7 @@ class Select {
|
|
|
1301
1377
|
}
|
|
1302
1378
|
valueChange(ev) {
|
|
1303
1379
|
if (this.listen && this.onValueChange) {
|
|
1304
|
-
this.onValueChange(this.
|
|
1380
|
+
this.onValueChange(this.getSelectedOptions());
|
|
1305
1381
|
}
|
|
1306
1382
|
return true;
|
|
1307
1383
|
}
|
|
@@ -1320,6 +1396,15 @@ class Select {
|
|
|
1320
1396
|
if (m.attributeName === 'class') {
|
|
1321
1397
|
classChanged = true;
|
|
1322
1398
|
}
|
|
1399
|
+
if (m.type === 'childList') {
|
|
1400
|
+
for (const n of m.addedNodes) {
|
|
1401
|
+
if (n.nodeName === 'OPTION' && n.value === this.select.value) {
|
|
1402
|
+
this.select.dispatchEvent(new Event('change'));
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
optgroupOptionChanged = true;
|
|
1407
|
+
}
|
|
1323
1408
|
}
|
|
1324
1409
|
if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
|
|
1325
1410
|
optgroupOptionChanged = true;
|
|
@@ -1359,7 +1444,7 @@ class Select {
|
|
|
1359
1444
|
selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
|
|
1360
1445
|
selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
|
|
1361
1446
|
closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
|
|
1362
|
-
options: []
|
|
1447
|
+
options: []
|
|
1363
1448
|
};
|
|
1364
1449
|
const options = optgroup.childNodes;
|
|
1365
1450
|
for (const o of options) {
|
|
@@ -1376,26 +1461,26 @@ class Select {
|
|
|
1376
1461
|
text: option.text,
|
|
1377
1462
|
html: option.dataset && option.dataset.html ? option.dataset.html : '',
|
|
1378
1463
|
selected: option.selected,
|
|
1379
|
-
display: option.style.display
|
|
1464
|
+
display: option.style.display !== 'none',
|
|
1380
1465
|
disabled: option.disabled,
|
|
1381
1466
|
mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
|
|
1382
1467
|
placeholder: option.dataset.placeholder === 'true',
|
|
1383
1468
|
class: option.className,
|
|
1384
1469
|
style: option.style.cssText,
|
|
1385
|
-
data: option.dataset
|
|
1470
|
+
data: option.dataset
|
|
1386
1471
|
};
|
|
1387
1472
|
}
|
|
1388
|
-
|
|
1389
|
-
let
|
|
1390
|
-
const
|
|
1391
|
-
for (const o of
|
|
1473
|
+
getSelectedOptions() {
|
|
1474
|
+
let options = [];
|
|
1475
|
+
const opts = this.select.childNodes;
|
|
1476
|
+
for (const o of opts) {
|
|
1392
1477
|
if (o.nodeName === 'OPTGROUP') {
|
|
1393
1478
|
const optgroupOptions = o.childNodes;
|
|
1394
1479
|
for (const oo of optgroupOptions) {
|
|
1395
1480
|
if (oo.nodeName === 'OPTION') {
|
|
1396
1481
|
const option = oo;
|
|
1397
1482
|
if (option.selected) {
|
|
1398
|
-
|
|
1483
|
+
options.push(this.getDataFromOption(option));
|
|
1399
1484
|
}
|
|
1400
1485
|
}
|
|
1401
1486
|
}
|
|
@@ -1403,13 +1488,16 @@ class Select {
|
|
|
1403
1488
|
if (o.nodeName === 'OPTION') {
|
|
1404
1489
|
const option = o;
|
|
1405
1490
|
if (option.selected) {
|
|
1406
|
-
|
|
1491
|
+
options.push(this.getDataFromOption(option));
|
|
1407
1492
|
}
|
|
1408
1493
|
}
|
|
1409
1494
|
}
|
|
1410
|
-
return
|
|
1495
|
+
return options;
|
|
1411
1496
|
}
|
|
1412
|
-
|
|
1497
|
+
getSelectedValues() {
|
|
1498
|
+
return this.getSelectedOptions().map((option) => option.value);
|
|
1499
|
+
}
|
|
1500
|
+
setSelected(ids) {
|
|
1413
1501
|
this.changeListen(false);
|
|
1414
1502
|
const options = this.select.childNodes;
|
|
1415
1503
|
for (const o of options) {
|
|
@@ -1419,13 +1507,34 @@ class Select {
|
|
|
1419
1507
|
for (const oo of optgroupOptions) {
|
|
1420
1508
|
if (oo.nodeName === 'OPTION') {
|
|
1421
1509
|
const option = oo;
|
|
1422
|
-
option.selected =
|
|
1510
|
+
option.selected = ids.includes(option.id);
|
|
1423
1511
|
}
|
|
1424
1512
|
}
|
|
1425
1513
|
}
|
|
1426
1514
|
if (o.nodeName === 'OPTION') {
|
|
1427
1515
|
const option = o;
|
|
1428
|
-
option.selected =
|
|
1516
|
+
option.selected = ids.includes(option.id);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
this.changeListen(true);
|
|
1520
|
+
}
|
|
1521
|
+
setSelectedByValue(values) {
|
|
1522
|
+
this.changeListen(false);
|
|
1523
|
+
const options = this.select.childNodes;
|
|
1524
|
+
for (const o of options) {
|
|
1525
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
1526
|
+
const optgroup = o;
|
|
1527
|
+
const optgroupOptions = optgroup.childNodes;
|
|
1528
|
+
for (const oo of optgroupOptions) {
|
|
1529
|
+
if (oo.nodeName === 'OPTION') {
|
|
1530
|
+
const option = oo;
|
|
1531
|
+
option.selected = values.includes(option.value);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
if (o.nodeName === 'OPTION') {
|
|
1536
|
+
const option = o;
|
|
1537
|
+
option.selected = values.includes(option.value);
|
|
1429
1538
|
}
|
|
1430
1539
|
}
|
|
1431
1540
|
this.changeListen(true);
|
|
@@ -1459,7 +1568,7 @@ class Select {
|
|
|
1459
1568
|
this.select.appendChild(this.createOption(d));
|
|
1460
1569
|
}
|
|
1461
1570
|
}
|
|
1462
|
-
this.select.dispatchEvent(new Event('change'));
|
|
1571
|
+
this.select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1463
1572
|
this.changeListen(true);
|
|
1464
1573
|
}
|
|
1465
1574
|
createOptgroup(optgroup) {
|
|
@@ -1493,7 +1602,7 @@ class Select {
|
|
|
1493
1602
|
if (info.disabled) {
|
|
1494
1603
|
optionEl.disabled = true;
|
|
1495
1604
|
}
|
|
1496
|
-
if (info.display
|
|
1605
|
+
if (!info.display) {
|
|
1497
1606
|
optionEl.style.display = 'none';
|
|
1498
1607
|
}
|
|
1499
1608
|
if (info.placeholder) {
|
|
@@ -1544,6 +1653,7 @@ class Settings {
|
|
|
1544
1653
|
this.disabled = settings.disabled !== undefined ? settings.disabled : false;
|
|
1545
1654
|
this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
|
|
1546
1655
|
this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
|
|
1656
|
+
this.focusSearch = settings.focusSearch !== undefined ? settings.focusSearch : true;
|
|
1547
1657
|
this.ariaLabel = settings.ariaLabel || 'Combobox';
|
|
1548
1658
|
this.searchPlaceholder = settings.searchPlaceholder || 'Search';
|
|
1549
1659
|
this.searchText = settings.searchText || 'No Results';
|
|
@@ -1563,6 +1673,7 @@ class Settings {
|
|
|
1563
1673
|
this.timeoutDelay = settings.timeoutDelay || 200;
|
|
1564
1674
|
this.maxValuesShown = settings.maxValuesShown || 20;
|
|
1565
1675
|
this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
|
|
1676
|
+
this.addableText = settings.addableText || 'Press "Enter" to add {value}';
|
|
1566
1677
|
}
|
|
1567
1678
|
}
|
|
1568
1679
|
|
|
@@ -1580,7 +1691,7 @@ class SlimSelect {
|
|
|
1580
1691
|
beforeOpen: undefined,
|
|
1581
1692
|
afterOpen: undefined,
|
|
1582
1693
|
beforeClose: undefined,
|
|
1583
|
-
afterClose: undefined
|
|
1694
|
+
afterClose: undefined
|
|
1584
1695
|
};
|
|
1585
1696
|
this.windowResize = debounce(() => {
|
|
1586
1697
|
if (!this.settings.isOpen && !this.settings.isFullOpen) {
|
|
@@ -1624,6 +1735,7 @@ class SlimSelect {
|
|
|
1624
1735
|
this.destroy();
|
|
1625
1736
|
}
|
|
1626
1737
|
this.settings = new Settings(config.settings);
|
|
1738
|
+
this.cssClasses = new CssClasses(config.cssClasses);
|
|
1627
1739
|
const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
|
|
1628
1740
|
for (const key in config.events) {
|
|
1629
1741
|
if (!config.events.hasOwnProperty(key)) {
|
|
@@ -1643,8 +1755,8 @@ class SlimSelect {
|
|
|
1643
1755
|
this.select = new Select(this.selectEl);
|
|
1644
1756
|
this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
|
|
1645
1757
|
this.select.hideUI();
|
|
1646
|
-
this.select.onValueChange = (
|
|
1647
|
-
this.setSelected(
|
|
1758
|
+
this.select.onValueChange = (options) => {
|
|
1759
|
+
this.setSelected(options.map((option) => option.id));
|
|
1648
1760
|
};
|
|
1649
1761
|
this.select.onClassChange = (classes) => {
|
|
1650
1762
|
this.settings.class = classes;
|
|
@@ -1673,9 +1785,9 @@ class SlimSelect {
|
|
|
1673
1785
|
addOption: this.addOption.bind(this),
|
|
1674
1786
|
search: this.search.bind(this),
|
|
1675
1787
|
beforeChange: this.events.beforeChange,
|
|
1676
|
-
afterChange: this.events.afterChange
|
|
1788
|
+
afterChange: this.events.afterChange
|
|
1677
1789
|
};
|
|
1678
|
-
this.render = new Render(this.settings, this.store, renderCallbacks);
|
|
1790
|
+
this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks);
|
|
1679
1791
|
this.render.renderValues();
|
|
1680
1792
|
this.render.renderOptions(this.store.getData());
|
|
1681
1793
|
const selectAriaLabel = this.selectEl.getAttribute('aria-label');
|
|
@@ -1734,11 +1846,27 @@ class SlimSelect {
|
|
|
1734
1846
|
}
|
|
1735
1847
|
}
|
|
1736
1848
|
getSelected() {
|
|
1737
|
-
|
|
1849
|
+
let options = this.store.getSelectedOptions();
|
|
1850
|
+
if (this.settings.keepOrder) {
|
|
1851
|
+
options = this.store.selectedOrderOptions(options);
|
|
1852
|
+
}
|
|
1853
|
+
return options.map((option) => option.value);
|
|
1738
1854
|
}
|
|
1739
|
-
setSelected(
|
|
1855
|
+
setSelected(values, runAfterChange = true) {
|
|
1740
1856
|
const selected = this.store.getSelected();
|
|
1741
|
-
this.store.
|
|
1857
|
+
const options = this.store.getDataOptions();
|
|
1858
|
+
values = Array.isArray(values) ? values : [values];
|
|
1859
|
+
const ids = [];
|
|
1860
|
+
for (const value of values) {
|
|
1861
|
+
if (options.find((option) => option.id == value)) {
|
|
1862
|
+
ids.push(value);
|
|
1863
|
+
continue;
|
|
1864
|
+
}
|
|
1865
|
+
for (const option of options.filter((option) => option.value == value)) {
|
|
1866
|
+
ids.push(option.id);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
this.store.setSelectedBy('id', ids);
|
|
1742
1870
|
const data = this.store.getData();
|
|
1743
1871
|
this.select.updateOptions(data);
|
|
1744
1872
|
this.render.renderValues();
|
|
@@ -1773,7 +1901,7 @@ class SlimSelect {
|
|
|
1773
1901
|
this.events.beforeOpen();
|
|
1774
1902
|
}
|
|
1775
1903
|
this.render.open();
|
|
1776
|
-
if (this.settings.showSearch) {
|
|
1904
|
+
if (this.settings.showSearch && this.settings.focusSearch) {
|
|
1777
1905
|
this.render.searchFocus();
|
|
1778
1906
|
}
|
|
1779
1907
|
this.settings.isOpen = true;
|