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.cjs.js
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
class CssClasses {
|
|
4
|
+
constructor(classes) {
|
|
5
|
+
if (!classes) {
|
|
6
|
+
classes = {};
|
|
7
|
+
}
|
|
8
|
+
this.main = classes.main || 'ss-main';
|
|
9
|
+
this.placeholder = classes.placeholder || 'ss-placeholder';
|
|
10
|
+
this.values = classes.values || 'ss-values';
|
|
11
|
+
this.single = classes.single || 'ss-single';
|
|
12
|
+
this.max = classes.max || 'ss-max';
|
|
13
|
+
this.value = classes.value || 'ss-value';
|
|
14
|
+
this.valueText = classes.valueText || 'ss-value-text';
|
|
15
|
+
this.valueDelete = classes.valueDelete || 'ss-value-delete';
|
|
16
|
+
this.valueOut = classes.valueOut || 'ss-value-out';
|
|
17
|
+
this.deselect = classes.deselect || 'ss-deselect';
|
|
18
|
+
this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10';
|
|
19
|
+
this.arrow = classes.arrow || 'ss-arrow';
|
|
20
|
+
this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30';
|
|
21
|
+
this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70';
|
|
22
|
+
this.content = classes.content || 'ss-content';
|
|
23
|
+
this.openAbove = classes.openAbove || 'ss-open-above';
|
|
24
|
+
this.openBelow = classes.openBelow || 'ss-open-below';
|
|
25
|
+
this.search = classes.search || 'ss-search';
|
|
26
|
+
this.searchHighlighter = classes.searchHighlighter || 'ss-search-highlight';
|
|
27
|
+
this.searching = classes.searching || 'ss-searching';
|
|
28
|
+
this.addable = classes.addable || 'ss-addable';
|
|
29
|
+
this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50';
|
|
30
|
+
this.list = classes.list || 'ss-list';
|
|
31
|
+
this.optgroup = classes.optgroup || 'ss-optgroup';
|
|
32
|
+
this.optgroupLabel = classes.optgroupLabel || 'ss-optgroup-label';
|
|
33
|
+
this.optgroupLabelText = classes.optgroupLabelText || 'ss-optgroup-label-text';
|
|
34
|
+
this.optgroupActions = classes.optgroupActions || 'ss-optgroup-actions';
|
|
35
|
+
this.optgroupSelectAll = classes.optgroupSelectAll || 'ss-selectall';
|
|
36
|
+
this.optgroupSelectAllBox = classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50';
|
|
37
|
+
this.optgroupSelectAllCheck = classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10';
|
|
38
|
+
this.optgroupClosable = classes.optgroupClosable || 'ss-closable';
|
|
39
|
+
this.option = classes.option || 'ss-option';
|
|
40
|
+
this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10';
|
|
41
|
+
this.highlighted = classes.highlighted || 'ss-highlighted';
|
|
42
|
+
this.open = classes.open || 'ss-open';
|
|
43
|
+
this.close = classes.close || 'ss-close';
|
|
44
|
+
this.selected = classes.selected || 'ss-selected';
|
|
45
|
+
this.error = classes.error || 'ss-error';
|
|
46
|
+
this.disabled = classes.disabled || 'ss-disabled';
|
|
47
|
+
this.hide = classes.hide || 'ss-hide';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
3
51
|
function generateID() {
|
|
4
52
|
return Math.random().toString(36).substring(2, 10);
|
|
5
53
|
}
|
|
@@ -87,6 +135,7 @@ class Store {
|
|
|
87
135
|
constructor(type, data) {
|
|
88
136
|
this.selectType = 'single';
|
|
89
137
|
this.data = [];
|
|
138
|
+
this.selectedOrder = [];
|
|
90
139
|
this.selectType = type;
|
|
91
140
|
this.setData(data);
|
|
92
141
|
}
|
|
@@ -101,12 +150,18 @@ class Store {
|
|
|
101
150
|
}
|
|
102
151
|
if ('options' in dataObj && dataObj.options) {
|
|
103
152
|
for (let option of dataObj.options) {
|
|
104
|
-
|
|
153
|
+
const validationError = this.validateOption(option);
|
|
154
|
+
if (validationError) {
|
|
155
|
+
return validationError;
|
|
156
|
+
}
|
|
105
157
|
}
|
|
106
158
|
}
|
|
107
159
|
}
|
|
108
160
|
else if (dataObj instanceof Option || 'text' in dataObj) {
|
|
109
|
-
|
|
161
|
+
const validationError = this.validateOption(dataObj);
|
|
162
|
+
if (validationError) {
|
|
163
|
+
return validationError;
|
|
164
|
+
}
|
|
110
165
|
}
|
|
111
166
|
else {
|
|
112
167
|
return new Error('Data object must be a valid optgroup or option');
|
|
@@ -143,7 +198,7 @@ class Store {
|
|
|
143
198
|
setData(data) {
|
|
144
199
|
this.data = this.partialToFullData(data);
|
|
145
200
|
if (this.selectType === 'single') {
|
|
146
|
-
this.setSelectedBy('
|
|
201
|
+
this.setSelectedBy('id', this.getSelected());
|
|
147
202
|
}
|
|
148
203
|
}
|
|
149
204
|
getData() {
|
|
@@ -152,12 +207,19 @@ class Store {
|
|
|
152
207
|
getDataOptions() {
|
|
153
208
|
return this.filter(null, false);
|
|
154
209
|
}
|
|
155
|
-
addOption(option) {
|
|
156
|
-
|
|
210
|
+
addOption(option, addToStart = false) {
|
|
211
|
+
if (addToStart) {
|
|
212
|
+
let data = [new Option(option)];
|
|
213
|
+
this.setData(data.concat(this.getData()));
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.setData(this.getData().concat(new Option(option)));
|
|
217
|
+
}
|
|
157
218
|
}
|
|
158
219
|
setSelectedBy(selectedType, selectedValues) {
|
|
159
220
|
let firstOption = null;
|
|
160
221
|
let hasSelected = false;
|
|
222
|
+
const selectedObjects = [];
|
|
161
223
|
for (let dataObj of this.data) {
|
|
162
224
|
if (dataObj instanceof Optgroup) {
|
|
163
225
|
for (let option of dataObj.options) {
|
|
@@ -165,8 +227,11 @@ class Store {
|
|
|
165
227
|
firstOption = option;
|
|
166
228
|
}
|
|
167
229
|
option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
|
|
168
|
-
if (option.selected
|
|
169
|
-
|
|
230
|
+
if (option.selected) {
|
|
231
|
+
selectedObjects.push(option);
|
|
232
|
+
if (this.selectType === 'single') {
|
|
233
|
+
hasSelected = true;
|
|
234
|
+
}
|
|
170
235
|
}
|
|
171
236
|
}
|
|
172
237
|
}
|
|
@@ -175,36 +240,35 @@ class Store {
|
|
|
175
240
|
firstOption = dataObj;
|
|
176
241
|
}
|
|
177
242
|
dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
|
|
178
|
-
if (dataObj.selected
|
|
179
|
-
|
|
243
|
+
if (dataObj.selected) {
|
|
244
|
+
selectedObjects.push(dataObj);
|
|
245
|
+
if (this.selectType === 'single') {
|
|
246
|
+
hasSelected = true;
|
|
247
|
+
}
|
|
180
248
|
}
|
|
181
249
|
}
|
|
182
250
|
}
|
|
183
251
|
if (this.selectType === 'single' && firstOption && !hasSelected) {
|
|
184
252
|
firstOption.selected = true;
|
|
253
|
+
selectedObjects.push(firstOption);
|
|
185
254
|
}
|
|
255
|
+
const selectedIds = selectedValues.map((value) => {
|
|
256
|
+
var _a;
|
|
257
|
+
return ((_a = selectedObjects.find((option) => option[selectedType] === value)) === null || _a === void 0 ? void 0 : _a.id) || '';
|
|
258
|
+
});
|
|
259
|
+
this.selectedOrder = selectedIds;
|
|
186
260
|
}
|
|
187
261
|
getSelected() {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
});
|
|
193
|
-
return selectedValues;
|
|
262
|
+
return this.getSelectedOptions().map((option) => option.id);
|
|
263
|
+
}
|
|
264
|
+
getSelectedValues() {
|
|
265
|
+
return this.getSelectedOptions().map((option) => option.value);
|
|
194
266
|
}
|
|
195
267
|
getSelectedOptions() {
|
|
196
268
|
return this.filter((opt) => {
|
|
197
269
|
return opt.selected;
|
|
198
270
|
}, false);
|
|
199
271
|
}
|
|
200
|
-
getSelectedIDs() {
|
|
201
|
-
let selectedOptions = this.getSelectedOptions();
|
|
202
|
-
let selectedIDs = [];
|
|
203
|
-
selectedOptions.forEach((op) => {
|
|
204
|
-
selectedIDs.push(op.id);
|
|
205
|
-
});
|
|
206
|
-
return selectedIDs;
|
|
207
|
-
}
|
|
208
272
|
getOptgroupByID(id) {
|
|
209
273
|
for (let dataObj of this.data) {
|
|
210
274
|
if (dataObj instanceof Optgroup && dataObj.id === id) {
|
|
@@ -275,54 +339,35 @@ class Store {
|
|
|
275
339
|
});
|
|
276
340
|
return dataSearch;
|
|
277
341
|
}
|
|
342
|
+
selectedOrderOptions(options) {
|
|
343
|
+
const newOrder = [];
|
|
344
|
+
this.selectedOrder.forEach((id) => {
|
|
345
|
+
const option = options.find((opt) => opt.id === id);
|
|
346
|
+
if (option) {
|
|
347
|
+
newOrder.push(option);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
options.forEach((option) => {
|
|
351
|
+
let isIn = false;
|
|
352
|
+
newOrder.forEach((selectedOption) => {
|
|
353
|
+
if (option.id === selectedOption.id) {
|
|
354
|
+
isIn = true;
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
if (!isIn) {
|
|
359
|
+
newOrder.push(option);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return newOrder;
|
|
363
|
+
}
|
|
278
364
|
}
|
|
279
365
|
|
|
280
366
|
class Render {
|
|
281
|
-
constructor(settings, store, callbacks) {
|
|
282
|
-
this.classes = {
|
|
283
|
-
main: 'ss-main',
|
|
284
|
-
placeholder: 'ss-placeholder',
|
|
285
|
-
values: 'ss-values',
|
|
286
|
-
single: 'ss-single',
|
|
287
|
-
max: 'ss-max',
|
|
288
|
-
value: 'ss-value',
|
|
289
|
-
valueText: 'ss-value-text',
|
|
290
|
-
valueDelete: 'ss-value-delete',
|
|
291
|
-
valueOut: 'ss-value-out',
|
|
292
|
-
deselect: 'ss-deselect',
|
|
293
|
-
deselectPath: 'M10,10 L90,90 M10,90 L90,10',
|
|
294
|
-
arrow: 'ss-arrow',
|
|
295
|
-
arrowClose: 'M10,30 L50,70 L90,30',
|
|
296
|
-
arrowOpen: 'M10,70 L50,30 L90,70',
|
|
297
|
-
content: 'ss-content',
|
|
298
|
-
openAbove: 'ss-open-above',
|
|
299
|
-
openBelow: 'ss-open-below',
|
|
300
|
-
search: 'ss-search',
|
|
301
|
-
searchHighlighter: 'ss-search-highlight',
|
|
302
|
-
searching: 'ss-searching',
|
|
303
|
-
addable: 'ss-addable',
|
|
304
|
-
addablePath: 'M50,10 L50,90 M10,50 L90,50',
|
|
305
|
-
list: 'ss-list',
|
|
306
|
-
optgroup: 'ss-optgroup',
|
|
307
|
-
optgroupLabel: 'ss-optgroup-label',
|
|
308
|
-
optgroupLabelText: 'ss-optgroup-label-text',
|
|
309
|
-
optgroupActions: 'ss-optgroup-actions',
|
|
310
|
-
optgroupSelectAll: 'ss-selectall',
|
|
311
|
-
optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
|
|
312
|
-
optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
|
|
313
|
-
optgroupClosable: 'ss-closable',
|
|
314
|
-
option: 'ss-option',
|
|
315
|
-
optionDelete: 'M10,10 L90,90 M10,90 L90,10',
|
|
316
|
-
highlighted: 'ss-highlighted',
|
|
317
|
-
open: 'ss-open',
|
|
318
|
-
close: 'ss-close',
|
|
319
|
-
selected: 'ss-selected',
|
|
320
|
-
error: 'ss-error',
|
|
321
|
-
disabled: 'ss-disabled',
|
|
322
|
-
hide: 'ss-hide',
|
|
323
|
-
};
|
|
367
|
+
constructor(settings, classes, store, callbacks) {
|
|
324
368
|
this.store = store;
|
|
325
369
|
this.settings = settings;
|
|
370
|
+
this.classes = classes;
|
|
326
371
|
this.callbacks = callbacks;
|
|
327
372
|
this.main = this.mainDiv();
|
|
328
373
|
this.content = this.contentDiv();
|
|
@@ -418,7 +463,7 @@ class Render {
|
|
|
418
463
|
this.callbacks.close();
|
|
419
464
|
return false;
|
|
420
465
|
}
|
|
421
|
-
return
|
|
466
|
+
return true;
|
|
422
467
|
};
|
|
423
468
|
main.onclick = (e) => {
|
|
424
469
|
if (this.settings.disabled) {
|
|
@@ -456,8 +501,8 @@ class Render {
|
|
|
456
501
|
}
|
|
457
502
|
else {
|
|
458
503
|
const firstOption = this.store.getFirstOption();
|
|
459
|
-
const
|
|
460
|
-
this.callbacks.setSelected(
|
|
504
|
+
const id = firstOption ? firstOption.id : '';
|
|
505
|
+
this.callbacks.setSelected(id, false);
|
|
461
506
|
}
|
|
462
507
|
if (this.settings.closeOnSelect) {
|
|
463
508
|
this.callbacks.close();
|
|
@@ -490,12 +535,12 @@ class Render {
|
|
|
490
535
|
deselect: {
|
|
491
536
|
main: deselect,
|
|
492
537
|
svg: deselectSvg,
|
|
493
|
-
path: deselectPath
|
|
538
|
+
path: deselectPath
|
|
494
539
|
},
|
|
495
540
|
arrow: {
|
|
496
541
|
main: arrow,
|
|
497
|
-
path: arrowPath
|
|
498
|
-
}
|
|
542
|
+
path: arrowPath
|
|
543
|
+
}
|
|
499
544
|
};
|
|
500
545
|
}
|
|
501
546
|
mainFocus(eventType) {
|
|
@@ -581,6 +626,9 @@ class Render {
|
|
|
581
626
|
maxValuesMessage.remove();
|
|
582
627
|
}
|
|
583
628
|
}
|
|
629
|
+
if (this.settings.keepOrder) {
|
|
630
|
+
selectedOptions = this.store.selectedOrderOptions(selectedOptions);
|
|
631
|
+
}
|
|
584
632
|
let removeNodes = [];
|
|
585
633
|
for (let i = 0; i < currentNodes.length; i++) {
|
|
586
634
|
const node = currentNodes[i];
|
|
@@ -634,7 +682,7 @@ class Render {
|
|
|
634
682
|
value.dataset.id = option.id;
|
|
635
683
|
const text = document.createElement('div');
|
|
636
684
|
text.classList.add(this.classes.valueText);
|
|
637
|
-
text.
|
|
685
|
+
text.textContent = option.text;
|
|
638
686
|
value.appendChild(text);
|
|
639
687
|
if (!option.mandatory) {
|
|
640
688
|
const deleteDiv = document.createElement('div');
|
|
@@ -657,18 +705,18 @@ class Render {
|
|
|
657
705
|
shouldDelete = this.callbacks.beforeChange(after, before) === true;
|
|
658
706
|
}
|
|
659
707
|
if (shouldDelete) {
|
|
660
|
-
let
|
|
708
|
+
let selectedIds = [];
|
|
661
709
|
for (const o of after) {
|
|
662
710
|
if (o instanceof Optgroup) {
|
|
663
711
|
for (const c of o.options) {
|
|
664
|
-
|
|
712
|
+
selectedIds.push(c.id);
|
|
665
713
|
}
|
|
666
714
|
}
|
|
667
715
|
if (o instanceof Option) {
|
|
668
|
-
|
|
716
|
+
selectedIds.push(o.id);
|
|
669
717
|
}
|
|
670
718
|
}
|
|
671
|
-
this.callbacks.setSelected(
|
|
719
|
+
this.callbacks.setSelected(selectedIds, false);
|
|
672
720
|
if (this.settings.closeOnSelect) {
|
|
673
721
|
this.callbacks.close();
|
|
674
722
|
}
|
|
@@ -698,7 +746,7 @@ class Render {
|
|
|
698
746
|
return {
|
|
699
747
|
main: main,
|
|
700
748
|
search: search,
|
|
701
|
-
list: list
|
|
749
|
+
list: list
|
|
702
750
|
};
|
|
703
751
|
}
|
|
704
752
|
moveContent() {
|
|
@@ -728,7 +776,7 @@ class Render {
|
|
|
728
776
|
main.classList.add(this.classes.search);
|
|
729
777
|
const searchReturn = {
|
|
730
778
|
main,
|
|
731
|
-
input
|
|
779
|
+
input
|
|
732
780
|
};
|
|
733
781
|
if (!this.settings.showSearch) {
|
|
734
782
|
main.classList.add(this.classes.hide);
|
|
@@ -756,9 +804,15 @@ class Render {
|
|
|
756
804
|
case 'Escape':
|
|
757
805
|
this.callbacks.close();
|
|
758
806
|
return false;
|
|
759
|
-
case 'Enter':
|
|
760
807
|
case ' ':
|
|
761
|
-
|
|
808
|
+
const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
|
|
809
|
+
if (highlighted) {
|
|
810
|
+
highlighted.click();
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
return true;
|
|
814
|
+
case 'Enter':
|
|
815
|
+
if (this.callbacks.addable) {
|
|
762
816
|
addable.click();
|
|
763
817
|
return false;
|
|
764
818
|
}
|
|
@@ -797,12 +851,12 @@ class Render {
|
|
|
797
851
|
let newOption = new Option(oo);
|
|
798
852
|
this.callbacks.addOption(newOption);
|
|
799
853
|
if (this.settings.isMultiple) {
|
|
800
|
-
let
|
|
801
|
-
|
|
802
|
-
this.callbacks.setSelected(
|
|
854
|
+
let ids = this.store.getSelected();
|
|
855
|
+
ids.push(newOption.id);
|
|
856
|
+
this.callbacks.setSelected(ids, true);
|
|
803
857
|
}
|
|
804
858
|
else {
|
|
805
|
-
this.callbacks.setSelected([newOption.
|
|
859
|
+
this.callbacks.setSelected([newOption.id], true);
|
|
806
860
|
}
|
|
807
861
|
this.callbacks.search('');
|
|
808
862
|
if (this.settings.closeOnSelect) {
|
|
@@ -820,9 +874,12 @@ class Render {
|
|
|
820
874
|
if (typeof value === 'string') {
|
|
821
875
|
runFinish({
|
|
822
876
|
text: value,
|
|
823
|
-
value: value
|
|
877
|
+
value: value
|
|
824
878
|
});
|
|
825
879
|
}
|
|
880
|
+
else if (addableValue instanceof Error) {
|
|
881
|
+
this.renderError(addableValue.message);
|
|
882
|
+
}
|
|
826
883
|
else {
|
|
827
884
|
runFinish(value);
|
|
828
885
|
}
|
|
@@ -831,9 +888,12 @@ class Render {
|
|
|
831
888
|
else if (typeof addableValue === 'string') {
|
|
832
889
|
runFinish({
|
|
833
890
|
text: addableValue,
|
|
834
|
-
value: addableValue
|
|
891
|
+
value: addableValue
|
|
835
892
|
});
|
|
836
893
|
}
|
|
894
|
+
else if (addableValue instanceof Error) {
|
|
895
|
+
this.renderError(addableValue.message);
|
|
896
|
+
}
|
|
837
897
|
else {
|
|
838
898
|
runFinish(addableValue);
|
|
839
899
|
}
|
|
@@ -843,7 +903,7 @@ class Render {
|
|
|
843
903
|
searchReturn.addable = {
|
|
844
904
|
main: addable,
|
|
845
905
|
svg: plus,
|
|
846
|
-
path: plusPath
|
|
906
|
+
path: plusPath
|
|
847
907
|
};
|
|
848
908
|
}
|
|
849
909
|
return searchReturn;
|
|
@@ -940,10 +1000,26 @@ class Render {
|
|
|
940
1000
|
if (data.length === 0) {
|
|
941
1001
|
const noResults = document.createElement('div');
|
|
942
1002
|
noResults.classList.add(this.classes.search);
|
|
943
|
-
|
|
1003
|
+
if (this.callbacks.addable) {
|
|
1004
|
+
noResults.innerHTML = this.settings.addableText.replace('{value}', this.content.search.input.value);
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
noResults.innerHTML = this.settings.searchText;
|
|
1008
|
+
}
|
|
944
1009
|
this.content.list.appendChild(noResults);
|
|
945
1010
|
return;
|
|
946
1011
|
}
|
|
1012
|
+
if (this.settings.allowDeselect && !this.settings.isMultiple) {
|
|
1013
|
+
const placeholderOption = this.store.filter((o) => o.placeholder, false);
|
|
1014
|
+
if (!placeholderOption.length) {
|
|
1015
|
+
this.store.addOption(new Option({
|
|
1016
|
+
text: '',
|
|
1017
|
+
value: '',
|
|
1018
|
+
selected: false,
|
|
1019
|
+
placeholder: true
|
|
1020
|
+
}), true);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
947
1023
|
for (const d of data) {
|
|
948
1024
|
if (d instanceof Optgroup) {
|
|
949
1025
|
const optgroupEl = document.createElement('div');
|
|
@@ -990,7 +1066,7 @@ class Render {
|
|
|
990
1066
|
if (allSelected) {
|
|
991
1067
|
const newSelected = currentSelected.filter((s) => {
|
|
992
1068
|
for (const o of d.options) {
|
|
993
|
-
if (s === o.
|
|
1069
|
+
if (s === o.id) {
|
|
994
1070
|
return false;
|
|
995
1071
|
}
|
|
996
1072
|
}
|
|
@@ -1000,7 +1076,7 @@ class Render {
|
|
|
1000
1076
|
return;
|
|
1001
1077
|
}
|
|
1002
1078
|
else {
|
|
1003
|
-
const newSelected = currentSelected.concat(d.options.map((o) => o.
|
|
1079
|
+
const newSelected = currentSelected.concat(d.options.map((o) => o.id));
|
|
1004
1080
|
for (const o of d.options) {
|
|
1005
1081
|
if (!this.store.getOptionByID(o.id)) {
|
|
1006
1082
|
this.callbacks.addOption(o);
|
|
@@ -1157,7 +1233,7 @@ class Render {
|
|
|
1157
1233
|
if (!this.store.getOptionByID(elementID)) {
|
|
1158
1234
|
this.callbacks.addOption(option);
|
|
1159
1235
|
}
|
|
1160
|
-
this.callbacks.setSelected(after.map((o) => o.
|
|
1236
|
+
this.callbacks.setSelected(after.map((o) => o.id), false);
|
|
1161
1237
|
if (this.settings.closeOnSelect) {
|
|
1162
1238
|
this.callbacks.close();
|
|
1163
1239
|
}
|
|
@@ -1174,7 +1250,7 @@ class Render {
|
|
|
1174
1250
|
}
|
|
1175
1251
|
highlightText(str, search, className) {
|
|
1176
1252
|
let completedString = str;
|
|
1177
|
-
const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
|
|
1253
|
+
const regex = new RegExp('(?![^<]*>)(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
|
|
1178
1254
|
if (!str.match(regex)) {
|
|
1179
1255
|
return str;
|
|
1180
1256
|
}
|
|
@@ -1263,7 +1339,7 @@ class Select {
|
|
|
1263
1339
|
this.select = select;
|
|
1264
1340
|
this.valueChange = this.valueChange.bind(this);
|
|
1265
1341
|
this.select.addEventListener('change', this.valueChange, {
|
|
1266
|
-
passive: true
|
|
1342
|
+
passive: true
|
|
1267
1343
|
});
|
|
1268
1344
|
this.observer = new MutationObserver(this.observeCall.bind(this));
|
|
1269
1345
|
this.changeListen(true);
|
|
@@ -1291,7 +1367,7 @@ class Select {
|
|
|
1291
1367
|
this.observer.observe(this.select, {
|
|
1292
1368
|
subtree: true,
|
|
1293
1369
|
childList: true,
|
|
1294
|
-
attributes: true
|
|
1370
|
+
attributes: true
|
|
1295
1371
|
});
|
|
1296
1372
|
}
|
|
1297
1373
|
}
|
|
@@ -1303,7 +1379,7 @@ class Select {
|
|
|
1303
1379
|
}
|
|
1304
1380
|
valueChange(ev) {
|
|
1305
1381
|
if (this.listen && this.onValueChange) {
|
|
1306
|
-
this.onValueChange(this.
|
|
1382
|
+
this.onValueChange(this.getSelectedOptions());
|
|
1307
1383
|
}
|
|
1308
1384
|
return true;
|
|
1309
1385
|
}
|
|
@@ -1322,6 +1398,15 @@ class Select {
|
|
|
1322
1398
|
if (m.attributeName === 'class') {
|
|
1323
1399
|
classChanged = true;
|
|
1324
1400
|
}
|
|
1401
|
+
if (m.type === 'childList') {
|
|
1402
|
+
for (const n of m.addedNodes) {
|
|
1403
|
+
if (n.nodeName === 'OPTION' && n.value === this.select.value) {
|
|
1404
|
+
this.select.dispatchEvent(new Event('change'));
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
optgroupOptionChanged = true;
|
|
1409
|
+
}
|
|
1325
1410
|
}
|
|
1326
1411
|
if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
|
|
1327
1412
|
optgroupOptionChanged = true;
|
|
@@ -1361,7 +1446,7 @@ class Select {
|
|
|
1361
1446
|
selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
|
|
1362
1447
|
selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
|
|
1363
1448
|
closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
|
|
1364
|
-
options: []
|
|
1449
|
+
options: []
|
|
1365
1450
|
};
|
|
1366
1451
|
const options = optgroup.childNodes;
|
|
1367
1452
|
for (const o of options) {
|
|
@@ -1378,26 +1463,26 @@ class Select {
|
|
|
1378
1463
|
text: option.text,
|
|
1379
1464
|
html: option.dataset && option.dataset.html ? option.dataset.html : '',
|
|
1380
1465
|
selected: option.selected,
|
|
1381
|
-
display: option.style.display
|
|
1466
|
+
display: option.style.display !== 'none',
|
|
1382
1467
|
disabled: option.disabled,
|
|
1383
1468
|
mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
|
|
1384
1469
|
placeholder: option.dataset.placeholder === 'true',
|
|
1385
1470
|
class: option.className,
|
|
1386
1471
|
style: option.style.cssText,
|
|
1387
|
-
data: option.dataset
|
|
1472
|
+
data: option.dataset
|
|
1388
1473
|
};
|
|
1389
1474
|
}
|
|
1390
|
-
|
|
1391
|
-
let
|
|
1392
|
-
const
|
|
1393
|
-
for (const o of
|
|
1475
|
+
getSelectedOptions() {
|
|
1476
|
+
let options = [];
|
|
1477
|
+
const opts = this.select.childNodes;
|
|
1478
|
+
for (const o of opts) {
|
|
1394
1479
|
if (o.nodeName === 'OPTGROUP') {
|
|
1395
1480
|
const optgroupOptions = o.childNodes;
|
|
1396
1481
|
for (const oo of optgroupOptions) {
|
|
1397
1482
|
if (oo.nodeName === 'OPTION') {
|
|
1398
1483
|
const option = oo;
|
|
1399
1484
|
if (option.selected) {
|
|
1400
|
-
|
|
1485
|
+
options.push(this.getDataFromOption(option));
|
|
1401
1486
|
}
|
|
1402
1487
|
}
|
|
1403
1488
|
}
|
|
@@ -1405,13 +1490,16 @@ class Select {
|
|
|
1405
1490
|
if (o.nodeName === 'OPTION') {
|
|
1406
1491
|
const option = o;
|
|
1407
1492
|
if (option.selected) {
|
|
1408
|
-
|
|
1493
|
+
options.push(this.getDataFromOption(option));
|
|
1409
1494
|
}
|
|
1410
1495
|
}
|
|
1411
1496
|
}
|
|
1412
|
-
return
|
|
1497
|
+
return options;
|
|
1413
1498
|
}
|
|
1414
|
-
|
|
1499
|
+
getSelectedValues() {
|
|
1500
|
+
return this.getSelectedOptions().map((option) => option.value);
|
|
1501
|
+
}
|
|
1502
|
+
setSelected(ids) {
|
|
1415
1503
|
this.changeListen(false);
|
|
1416
1504
|
const options = this.select.childNodes;
|
|
1417
1505
|
for (const o of options) {
|
|
@@ -1421,13 +1509,34 @@ class Select {
|
|
|
1421
1509
|
for (const oo of optgroupOptions) {
|
|
1422
1510
|
if (oo.nodeName === 'OPTION') {
|
|
1423
1511
|
const option = oo;
|
|
1424
|
-
option.selected =
|
|
1512
|
+
option.selected = ids.includes(option.id);
|
|
1425
1513
|
}
|
|
1426
1514
|
}
|
|
1427
1515
|
}
|
|
1428
1516
|
if (o.nodeName === 'OPTION') {
|
|
1429
1517
|
const option = o;
|
|
1430
|
-
option.selected =
|
|
1518
|
+
option.selected = ids.includes(option.id);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
this.changeListen(true);
|
|
1522
|
+
}
|
|
1523
|
+
setSelectedByValue(values) {
|
|
1524
|
+
this.changeListen(false);
|
|
1525
|
+
const options = this.select.childNodes;
|
|
1526
|
+
for (const o of options) {
|
|
1527
|
+
if (o.nodeName === 'OPTGROUP') {
|
|
1528
|
+
const optgroup = o;
|
|
1529
|
+
const optgroupOptions = optgroup.childNodes;
|
|
1530
|
+
for (const oo of optgroupOptions) {
|
|
1531
|
+
if (oo.nodeName === 'OPTION') {
|
|
1532
|
+
const option = oo;
|
|
1533
|
+
option.selected = values.includes(option.value);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
if (o.nodeName === 'OPTION') {
|
|
1538
|
+
const option = o;
|
|
1539
|
+
option.selected = values.includes(option.value);
|
|
1431
1540
|
}
|
|
1432
1541
|
}
|
|
1433
1542
|
this.changeListen(true);
|
|
@@ -1461,7 +1570,7 @@ class Select {
|
|
|
1461
1570
|
this.select.appendChild(this.createOption(d));
|
|
1462
1571
|
}
|
|
1463
1572
|
}
|
|
1464
|
-
this.select.dispatchEvent(new Event('change'));
|
|
1573
|
+
this.select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1465
1574
|
this.changeListen(true);
|
|
1466
1575
|
}
|
|
1467
1576
|
createOptgroup(optgroup) {
|
|
@@ -1495,7 +1604,7 @@ class Select {
|
|
|
1495
1604
|
if (info.disabled) {
|
|
1496
1605
|
optionEl.disabled = true;
|
|
1497
1606
|
}
|
|
1498
|
-
if (info.display
|
|
1607
|
+
if (!info.display) {
|
|
1499
1608
|
optionEl.style.display = 'none';
|
|
1500
1609
|
}
|
|
1501
1610
|
if (info.placeholder) {
|
|
@@ -1546,6 +1655,7 @@ class Settings {
|
|
|
1546
1655
|
this.disabled = settings.disabled !== undefined ? settings.disabled : false;
|
|
1547
1656
|
this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
|
|
1548
1657
|
this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
|
|
1658
|
+
this.focusSearch = settings.focusSearch !== undefined ? settings.focusSearch : true;
|
|
1549
1659
|
this.ariaLabel = settings.ariaLabel || 'Combobox';
|
|
1550
1660
|
this.searchPlaceholder = settings.searchPlaceholder || 'Search';
|
|
1551
1661
|
this.searchText = settings.searchText || 'No Results';
|
|
@@ -1565,6 +1675,7 @@ class Settings {
|
|
|
1565
1675
|
this.timeoutDelay = settings.timeoutDelay || 200;
|
|
1566
1676
|
this.maxValuesShown = settings.maxValuesShown || 20;
|
|
1567
1677
|
this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
|
|
1678
|
+
this.addableText = settings.addableText || 'Press "Enter" to add {value}';
|
|
1568
1679
|
}
|
|
1569
1680
|
}
|
|
1570
1681
|
|
|
@@ -1582,7 +1693,7 @@ class SlimSelect {
|
|
|
1582
1693
|
beforeOpen: undefined,
|
|
1583
1694
|
afterOpen: undefined,
|
|
1584
1695
|
beforeClose: undefined,
|
|
1585
|
-
afterClose: undefined
|
|
1696
|
+
afterClose: undefined
|
|
1586
1697
|
};
|
|
1587
1698
|
this.windowResize = debounce(() => {
|
|
1588
1699
|
if (!this.settings.isOpen && !this.settings.isFullOpen) {
|
|
@@ -1626,6 +1737,7 @@ class SlimSelect {
|
|
|
1626
1737
|
this.destroy();
|
|
1627
1738
|
}
|
|
1628
1739
|
this.settings = new Settings(config.settings);
|
|
1740
|
+
this.cssClasses = new CssClasses(config.cssClasses);
|
|
1629
1741
|
const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
|
|
1630
1742
|
for (const key in config.events) {
|
|
1631
1743
|
if (!config.events.hasOwnProperty(key)) {
|
|
@@ -1645,8 +1757,8 @@ class SlimSelect {
|
|
|
1645
1757
|
this.select = new Select(this.selectEl);
|
|
1646
1758
|
this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
|
|
1647
1759
|
this.select.hideUI();
|
|
1648
|
-
this.select.onValueChange = (
|
|
1649
|
-
this.setSelected(
|
|
1760
|
+
this.select.onValueChange = (options) => {
|
|
1761
|
+
this.setSelected(options.map((option) => option.id));
|
|
1650
1762
|
};
|
|
1651
1763
|
this.select.onClassChange = (classes) => {
|
|
1652
1764
|
this.settings.class = classes;
|
|
@@ -1675,9 +1787,9 @@ class SlimSelect {
|
|
|
1675
1787
|
addOption: this.addOption.bind(this),
|
|
1676
1788
|
search: this.search.bind(this),
|
|
1677
1789
|
beforeChange: this.events.beforeChange,
|
|
1678
|
-
afterChange: this.events.afterChange
|
|
1790
|
+
afterChange: this.events.afterChange
|
|
1679
1791
|
};
|
|
1680
|
-
this.render = new Render(this.settings, this.store, renderCallbacks);
|
|
1792
|
+
this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks);
|
|
1681
1793
|
this.render.renderValues();
|
|
1682
1794
|
this.render.renderOptions(this.store.getData());
|
|
1683
1795
|
const selectAriaLabel = this.selectEl.getAttribute('aria-label');
|
|
@@ -1736,11 +1848,27 @@ class SlimSelect {
|
|
|
1736
1848
|
}
|
|
1737
1849
|
}
|
|
1738
1850
|
getSelected() {
|
|
1739
|
-
|
|
1851
|
+
let options = this.store.getSelectedOptions();
|
|
1852
|
+
if (this.settings.keepOrder) {
|
|
1853
|
+
options = this.store.selectedOrderOptions(options);
|
|
1854
|
+
}
|
|
1855
|
+
return options.map((option) => option.value);
|
|
1740
1856
|
}
|
|
1741
|
-
setSelected(
|
|
1857
|
+
setSelected(values, runAfterChange = true) {
|
|
1742
1858
|
const selected = this.store.getSelected();
|
|
1743
|
-
this.store.
|
|
1859
|
+
const options = this.store.getDataOptions();
|
|
1860
|
+
values = Array.isArray(values) ? values : [values];
|
|
1861
|
+
const ids = [];
|
|
1862
|
+
for (const value of values) {
|
|
1863
|
+
if (options.find((option) => option.id == value)) {
|
|
1864
|
+
ids.push(value);
|
|
1865
|
+
continue;
|
|
1866
|
+
}
|
|
1867
|
+
for (const option of options.filter((option) => option.value == value)) {
|
|
1868
|
+
ids.push(option.id);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
this.store.setSelectedBy('id', ids);
|
|
1744
1872
|
const data = this.store.getData();
|
|
1745
1873
|
this.select.updateOptions(data);
|
|
1746
1874
|
this.render.renderValues();
|
|
@@ -1775,7 +1903,7 @@ class SlimSelect {
|
|
|
1775
1903
|
this.events.beforeOpen();
|
|
1776
1904
|
}
|
|
1777
1905
|
this.render.open();
|
|
1778
|
-
if (this.settings.showSearch) {
|
|
1906
|
+
if (this.settings.showSearch && this.settings.focusSearch) {
|
|
1779
1907
|
this.render.searchFocus();
|
|
1780
1908
|
}
|
|
1781
1909
|
this.settings.isOpen = true;
|