@keenthemes/ktui 1.0.19 → 1.0.21
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/dist/ktui.js +690 -166
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +165 -31
- package/examples/image-input/file-upload-example.html +189 -0
- package/examples/select/remote-data_.html +5 -0
- package/examples/select/test-optimizations.html +227 -0
- package/examples/select/test-remote-search.html +151 -0
- package/examples/sticky/README.md +158 -0
- package/examples/sticky/debug-sticky.html +144 -0
- package/examples/sticky/test-runner.html +175 -0
- package/examples/sticky/test-sticky-logic.js +369 -0
- package/examples/sticky/test-sticky-positioning.html +386 -0
- package/examples/toast/example.html +52 -0
- package/lib/cjs/components/component.js +59 -5
- package/lib/cjs/components/component.js.map +1 -1
- package/lib/cjs/components/datatable/datatable-sort.js +4 -0
- package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +79 -12
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/image-input/image-input.js +10 -2
- package/lib/cjs/components/image-input/image-input.js.map +1 -1
- package/lib/cjs/components/select/combobox.js +50 -20
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/config.js +1 -0
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +4 -2
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/index.js.map +1 -1
- package/lib/cjs/components/select/option.js +2 -1
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/remote.js +50 -50
- package/lib/cjs/components/select/remote.js.map +1 -1
- package/lib/cjs/components/select/search.js +15 -5
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +273 -32
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.js +3 -1
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.js +6 -0
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/utils.js +23 -10
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/components/stepper/stepper.js +59 -12
- package/lib/cjs/components/stepper/stepper.js.map +1 -1
- package/lib/cjs/components/sticky/sticky.js +52 -14
- package/lib/cjs/components/sticky/sticky.js.map +1 -1
- package/lib/esm/components/component.js +59 -5
- package/lib/esm/components/component.js.map +1 -1
- package/lib/esm/components/datatable/datatable-sort.js +4 -0
- package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +78 -12
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/image-input/image-input.js +10 -2
- package/lib/esm/components/image-input/image-input.js.map +1 -1
- package/lib/esm/components/select/combobox.js +50 -20
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/config.js +1 -0
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +4 -2
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/index.js +1 -1
- package/lib/esm/components/select/index.js.map +1 -1
- package/lib/esm/components/select/option.js +2 -1
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/remote.js +50 -50
- package/lib/esm/components/select/remote.js.map +1 -1
- package/lib/esm/components/select/search.js +16 -6
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +273 -32
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.js +3 -1
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.js +6 -0
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/utils.js +23 -10
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/components/stepper/stepper.js +59 -12
- package/lib/esm/components/stepper/stepper.js.map +1 -1
- package/lib/esm/components/sticky/sticky.js +52 -14
- package/lib/esm/components/sticky/sticky.js.map +1 -1
- package/package.json +2 -2
- package/src/components/component.ts +19 -4
- package/src/components/datatable/datatable-sort.ts +6 -0
- package/src/components/datatable/datatable.ts +98 -15
- package/src/components/datatable/types.ts +5 -1
- package/src/components/image-input/image-input.ts +11 -2
- package/src/components/image-input/types.ts +1 -0
- package/src/components/input/input-group.css +1 -1
- package/src/components/input/input.css +1 -1
- package/src/components/scrollable/scrollable.css +3 -3
- package/src/components/select/combobox.ts +84 -34
- package/src/components/select/config.ts +2 -0
- package/src/components/select/dropdown.ts +20 -11
- package/src/components/select/index.ts +6 -1
- package/src/components/select/option.ts +7 -6
- package/src/components/select/remote.ts +51 -52
- package/src/components/select/search.ts +59 -44
- package/src/components/select/select.css +26 -17
- package/src/components/select/select.ts +472 -101
- package/src/components/select/tags.ts +9 -3
- package/src/components/select/templates.ts +10 -0
- package/src/components/select/utils.ts +55 -20
- package/src/components/select/variants.css +0 -1
- package/src/components/stepper/stepper.ts +2 -2
- package/src/components/sticky/sticky.ts +47 -16
- package/src/components/sticky/types.ts +3 -0
- package/src/components/table/table.css +1 -1
- package/src/components/textarea/textarea.css +1 -1
- package/src/components/toast/toast.css +84 -47
- package/src/components/toast/types.ts +3 -0
|
@@ -61,12 +61,16 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
61
61
|
// Core properties
|
|
62
62
|
_this._name = 'select';
|
|
63
63
|
_this._dataOptionPrefix = 'kt-'; // Use 'kt-' prefix to support data-kt-select-option attributes
|
|
64
|
+
// Cached DOM references for performance
|
|
65
|
+
_this._optionsContainer = null;
|
|
64
66
|
// State
|
|
65
67
|
_this._dropdownIsOpen = false;
|
|
66
68
|
_this._comboboxModule = null;
|
|
67
69
|
_this._tagsModule = null;
|
|
68
70
|
_this._dropdownModule = null;
|
|
69
71
|
_this._loadMoreIndicator = null;
|
|
72
|
+
_this._selectAllButton = null;
|
|
73
|
+
_this._selectAllButtonToggle = null;
|
|
70
74
|
_this._typeToSearchBuffer = new utils_1.TypeToSearchBuffer();
|
|
71
75
|
_this._mutationObserver = null;
|
|
72
76
|
// Search debounce timeout
|
|
@@ -112,6 +116,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
112
116
|
return;
|
|
113
117
|
if (this._config.debug)
|
|
114
118
|
console.log('Initializing remote data with URL:', this._config.dataUrl);
|
|
119
|
+
// For remote data, we need to create the HTML structure first
|
|
120
|
+
// so that the component can be properly initialized
|
|
121
|
+
this._createHtmlStructure();
|
|
122
|
+
this._setupElementReferences();
|
|
115
123
|
// Show loading state
|
|
116
124
|
this._renderLoadingState();
|
|
117
125
|
// Fetch remote data
|
|
@@ -130,7 +138,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
130
138
|
_this._generateOptionsHtml(_this._element);
|
|
131
139
|
if (_this._config.debug)
|
|
132
140
|
console.log('Generating options HTML from remote data');
|
|
133
|
-
|
|
141
|
+
// Update the dropdown to show the new options
|
|
142
|
+
_this._updateDropdownWithNewOptions();
|
|
143
|
+
// Complete the component setup with the fetched data
|
|
144
|
+
_this._completeRemoteSetup();
|
|
134
145
|
// Add pagination "Load More" button if needed
|
|
135
146
|
if (_this._config.pagination && _this._remoteModule.hasMorePages()) {
|
|
136
147
|
_this._addLoadMoreButton();
|
|
@@ -154,6 +165,108 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
154
165
|
var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
|
|
155
166
|
options.forEach(function (option) { return option.remove(); });
|
|
156
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* Unified method to render options in dropdown - eliminates code duplication
|
|
170
|
+
*/
|
|
171
|
+
KTSelect.prototype._renderOptionsInDropdown = function (optionsData, clearContainer) {
|
|
172
|
+
var _this = this;
|
|
173
|
+
if (clearContainer === void 0) { clearContainer = true; }
|
|
174
|
+
if (!this._dropdownContentElement)
|
|
175
|
+
return;
|
|
176
|
+
// Use cached options container for better performance
|
|
177
|
+
var optionsContainer = this._optionsContainer ||
|
|
178
|
+
this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
179
|
+
if (!optionsContainer)
|
|
180
|
+
return;
|
|
181
|
+
// Clear container if requested
|
|
182
|
+
if (clearContainer) {
|
|
183
|
+
optionsContainer.innerHTML = '';
|
|
184
|
+
}
|
|
185
|
+
// Use DocumentFragment for efficient DOM manipulation
|
|
186
|
+
var fragment = document.createDocumentFragment();
|
|
187
|
+
// Process options data
|
|
188
|
+
optionsData.forEach(function (optionData) {
|
|
189
|
+
var optionElement;
|
|
190
|
+
// Handle different input types
|
|
191
|
+
if (optionData instanceof HTMLOptionElement) {
|
|
192
|
+
// Skip empty placeholder options
|
|
193
|
+
if (optionData.value === '' && optionData.textContent.trim() === '') {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
optionElement = optionData;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Handle KTSelectOptionData objects - cast to ensure type safety
|
|
200
|
+
var dataItem = optionData;
|
|
201
|
+
optionElement = document.createElement('option');
|
|
202
|
+
optionElement.value = dataItem.id || '';
|
|
203
|
+
optionElement.textContent = dataItem.title || '';
|
|
204
|
+
if (dataItem.selected) {
|
|
205
|
+
optionElement.setAttribute('selected', 'selected');
|
|
206
|
+
}
|
|
207
|
+
if (dataItem.disabled) {
|
|
208
|
+
optionElement.setAttribute('disabled', 'disabled');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Create KTSelectOption instance for proper rendering
|
|
212
|
+
var selectOption = new option_1.KTSelectOption(optionElement, _this._config);
|
|
213
|
+
var renderedOption = selectOption.render();
|
|
214
|
+
// Add to fragment for batch DOM operation
|
|
215
|
+
fragment.appendChild(renderedOption);
|
|
216
|
+
});
|
|
217
|
+
// Batch append all options at once
|
|
218
|
+
optionsContainer.appendChild(fragment);
|
|
219
|
+
// Update options NodeList
|
|
220
|
+
this._options = this._wrapperElement.querySelectorAll('[data-kt-select-option]');
|
|
221
|
+
if (this._config.debug) {
|
|
222
|
+
console.log("Rendered ".concat(optionsData.length, " options in dropdown"));
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Update dropdown with new options from the original select element
|
|
227
|
+
*/
|
|
228
|
+
KTSelect.prototype._updateDropdownWithNewOptions = function () {
|
|
229
|
+
// Get all options from the original select element
|
|
230
|
+
var options = Array.from(this._element.querySelectorAll('option'));
|
|
231
|
+
// Use unified renderer
|
|
232
|
+
this._renderOptionsInDropdown(options, true);
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Complete the setup for remote data after HTML structure is created
|
|
236
|
+
*/
|
|
237
|
+
KTSelect.prototype._completeRemoteSetup = function () {
|
|
238
|
+
// Initialize options
|
|
239
|
+
this._preSelectOptions(this._element);
|
|
240
|
+
// Apply disabled state if needed
|
|
241
|
+
this._applyInitialDisabledState();
|
|
242
|
+
// Initialize search if enabled
|
|
243
|
+
if (this._config.enableSearch) {
|
|
244
|
+
this._initializeSearchModule();
|
|
245
|
+
}
|
|
246
|
+
// Initialize combobox if enabled
|
|
247
|
+
if (this._config.combobox) {
|
|
248
|
+
this._comboboxModule = new combobox_1.KTSelectCombobox(this);
|
|
249
|
+
}
|
|
250
|
+
// Initialize tags if enabled
|
|
251
|
+
if (this._config.tags) {
|
|
252
|
+
this._tagsModule = new tags_1.KTSelectTags(this);
|
|
253
|
+
}
|
|
254
|
+
// Initialize focus manager after dropdown element is created
|
|
255
|
+
this._focusManager = new utils_1.FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
|
|
256
|
+
// Initialize dropdown module after all elements are created
|
|
257
|
+
this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
|
|
258
|
+
// Update display and set ARIA attributes
|
|
259
|
+
this._updateDisplayAndAriaAttributes();
|
|
260
|
+
this.updateSelectedOptionDisplay();
|
|
261
|
+
this._setAriaAttributes();
|
|
262
|
+
// Update select all button state
|
|
263
|
+
this.updateSelectAllButtonState();
|
|
264
|
+
// Focus the first selected option or first option if nothing selected
|
|
265
|
+
this._focusSelectedOption();
|
|
266
|
+
// Attach event listeners after all modules are initialized
|
|
267
|
+
this._attachEventListeners();
|
|
268
|
+
this._observeNativeSelect();
|
|
269
|
+
};
|
|
157
270
|
/**
|
|
158
271
|
* Helper to show a dropdown message (error, loading, noResults)
|
|
159
272
|
*/
|
|
@@ -347,6 +460,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
347
460
|
this._updateDisplayAndAriaAttributes();
|
|
348
461
|
this.updateSelectedOptionDisplay();
|
|
349
462
|
this._setAriaAttributes();
|
|
463
|
+
// Update select all button state
|
|
464
|
+
this.updateSelectAllButtonState();
|
|
465
|
+
// Focus the first selected option or first option if nothing selected
|
|
466
|
+
this._focusSelectedOption();
|
|
350
467
|
// Attach event listeners after all modules are initialized
|
|
351
468
|
this._attachEventListeners();
|
|
352
469
|
this._observeNativeSelect();
|
|
@@ -366,13 +483,19 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
366
483
|
// Move classes from original select to wrapper and display elements
|
|
367
484
|
if (this._element.classList.length > 0) {
|
|
368
485
|
var originalClasses = Array.from(this._element.classList);
|
|
369
|
-
var displaySpecificClasses_1 = [
|
|
486
|
+
var displaySpecificClasses_1 = [
|
|
487
|
+
'kt-select',
|
|
488
|
+
'kt-select-sm',
|
|
489
|
+
'kt-select-lg',
|
|
490
|
+
];
|
|
370
491
|
var classesForWrapper = originalClasses.filter(function (className) { return !displaySpecificClasses_1.includes(className); });
|
|
371
492
|
if (classesForWrapper.length > 0) {
|
|
372
493
|
(_a = wrapperElement.classList).add.apply(_a, classesForWrapper);
|
|
373
494
|
}
|
|
374
495
|
// Move display-specific classes to display element
|
|
375
|
-
var classesForDisplay = originalClasses.filter(function (className) {
|
|
496
|
+
var classesForDisplay = originalClasses.filter(function (className) {
|
|
497
|
+
return displaySpecificClasses_1.includes(className);
|
|
498
|
+
});
|
|
376
499
|
if (classesForDisplay.length > 0) {
|
|
377
500
|
(_b = displayElement.classList).add.apply(_b, classesForDisplay);
|
|
378
501
|
}
|
|
@@ -385,9 +508,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
385
508
|
var searchElement = templates_1.defaultTemplates.search(this._config);
|
|
386
509
|
dropdownElement.appendChild(searchElement);
|
|
387
510
|
}
|
|
511
|
+
// Add select all button if needed
|
|
512
|
+
if (this._config.multiple && this._config.enableSelectAll) {
|
|
513
|
+
var selectAllElement = templates_1.defaultTemplates.selectAll(this._config);
|
|
514
|
+
dropdownElement.appendChild(selectAllElement);
|
|
515
|
+
}
|
|
388
516
|
// Create options container using template
|
|
389
517
|
var optionsContainer = templates_1.defaultTemplates.options(this._config);
|
|
390
|
-
// Add each option directly to the container
|
|
518
|
+
// Add each option directly to the container (only if options exist)
|
|
391
519
|
options.forEach(function (optionElement) {
|
|
392
520
|
// Skip empty placeholder options (only if BOTH value AND text are empty)
|
|
393
521
|
// This allows options with empty value but visible text to display in dropdown
|
|
@@ -414,13 +542,18 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
414
542
|
*/
|
|
415
543
|
KTSelect.prototype._setupElementReferences = function () {
|
|
416
544
|
this._wrapperElement = this._element.nextElementSibling;
|
|
545
|
+
// Safety check - ensure wrapper element exists
|
|
546
|
+
if (!this._wrapperElement) {
|
|
547
|
+
console.error('KTSelect: Wrapper element not found. HTML structure may not be created properly.');
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
417
550
|
// Get display element
|
|
418
551
|
this._displayElement = this._wrapperElement.querySelector("[data-kt-select-display]");
|
|
419
552
|
// Get dropdown content element - this is critical for dropdown functionality
|
|
420
553
|
this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown]");
|
|
421
554
|
if (!this._dropdownContentElement) {
|
|
422
|
-
console.
|
|
423
|
-
|
|
555
|
+
console.error('KTSelect: Dropdown content element not found', this._wrapperElement);
|
|
556
|
+
return;
|
|
424
557
|
}
|
|
425
558
|
// Get search input element - this is used for the search functionality
|
|
426
559
|
this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
|
|
@@ -428,6 +561,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
428
561
|
if (!this._searchInputElement) {
|
|
429
562
|
this._searchInputElement = this._displayElement;
|
|
430
563
|
}
|
|
564
|
+
this._selectAllButton = this._wrapperElement.querySelector('[data-kt-select-select-all]');
|
|
565
|
+
// Cache the options container for performance
|
|
566
|
+
this._optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
431
567
|
this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
432
568
|
};
|
|
433
569
|
/**
|
|
@@ -438,6 +574,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
438
574
|
document.addEventListener('click', this._handleDocumentClick.bind(this));
|
|
439
575
|
// Dropdown option click events
|
|
440
576
|
this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
|
|
577
|
+
if (this._selectAllButton) {
|
|
578
|
+
this._selectAllButtonToggle =
|
|
579
|
+
this._selectAllButton.querySelector('button');
|
|
580
|
+
if (this._selectAllButtonToggle) {
|
|
581
|
+
this._eventManager.addListener(this._selectAllButtonToggle, 'click', this._handleSelectAllClick.bind(this));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
441
584
|
// Attach centralized keyboard handler to the wrapper element.
|
|
442
585
|
// Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
|
|
443
586
|
if (this._wrapperElement) {
|
|
@@ -603,6 +746,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
603
746
|
this._fireEvent('show');
|
|
604
747
|
// Update ARIA states
|
|
605
748
|
this._setAriaAttributes();
|
|
749
|
+
// Update select all button state
|
|
750
|
+
this.updateSelectAllButtonState();
|
|
606
751
|
// Focus the first selected option or first option if nothing selected
|
|
607
752
|
this._focusSelectedOption();
|
|
608
753
|
};
|
|
@@ -830,6 +975,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
830
975
|
this._state.setSelectedOptions([]);
|
|
831
976
|
this.updateSelectedOptionDisplay();
|
|
832
977
|
this._updateSelectedOptionClass();
|
|
978
|
+
// Update select all button state
|
|
979
|
+
this.updateSelectAllButtonState();
|
|
833
980
|
// Dispatch change event
|
|
834
981
|
this._dispatchEvent('change');
|
|
835
982
|
this._fireEvent('change');
|
|
@@ -1094,6 +1241,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1094
1241
|
if (this._config.debug)
|
|
1095
1242
|
console.log('Multiple select mode - keeping dropdown open for additional selections');
|
|
1096
1243
|
// Don't close dropdown in multiple select mode to allow multiple selections
|
|
1244
|
+
this.updateSelectAllButtonState();
|
|
1097
1245
|
}
|
|
1098
1246
|
// Dispatch custom change event with additional data
|
|
1099
1247
|
this._dispatchEvent('change', {
|
|
@@ -1173,6 +1321,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1173
1321
|
var query = event.target.value;
|
|
1174
1322
|
// Check if the query is long enough
|
|
1175
1323
|
if (query.length < (this._config.searchMinLength || 0)) {
|
|
1324
|
+
// Restore original options if query is too short
|
|
1325
|
+
this._restoreOriginalOptions();
|
|
1176
1326
|
return;
|
|
1177
1327
|
}
|
|
1178
1328
|
// Debounce the search
|
|
@@ -1196,6 +1346,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1196
1346
|
if (_this._searchModule) {
|
|
1197
1347
|
_this._searchModule.refreshAfterSearch();
|
|
1198
1348
|
}
|
|
1349
|
+
_this.updateSelectAllButtonState();
|
|
1199
1350
|
})
|
|
1200
1351
|
.catch(function (error) {
|
|
1201
1352
|
console.error('Error updating search results:', error);
|
|
@@ -1226,7 +1377,36 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1226
1377
|
* @param message Error message
|
|
1227
1378
|
*/
|
|
1228
1379
|
KTSelect.prototype._renderSearchErrorState = function (message) {
|
|
1380
|
+
var _this = this;
|
|
1229
1381
|
this._showDropdownMessage('error', message);
|
|
1382
|
+
// Restore original options after error with a delay
|
|
1383
|
+
setTimeout(function () {
|
|
1384
|
+
_this._restoreOriginalOptions();
|
|
1385
|
+
}, 2000);
|
|
1386
|
+
};
|
|
1387
|
+
/**
|
|
1388
|
+
* Restore original options when search is cleared
|
|
1389
|
+
*/
|
|
1390
|
+
KTSelect.prototype._restoreOriginalOptions = function () {
|
|
1391
|
+
if (!this._dropdownContentElement || !this._originalOptionsHtml)
|
|
1392
|
+
return;
|
|
1393
|
+
// Use cached options container for better performance
|
|
1394
|
+
var optionsContainer = this._optionsContainer ||
|
|
1395
|
+
this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
1396
|
+
if (!optionsContainer)
|
|
1397
|
+
return;
|
|
1398
|
+
// Restore original options
|
|
1399
|
+
optionsContainer.innerHTML = this._originalOptionsHtml;
|
|
1400
|
+
// Update options NodeList
|
|
1401
|
+
this._options = this._wrapperElement.querySelectorAll('[data-kt-select-option]');
|
|
1402
|
+
// Refresh search module
|
|
1403
|
+
if (this._searchModule) {
|
|
1404
|
+
this._searchModule.refreshAfterSearch();
|
|
1405
|
+
}
|
|
1406
|
+
this.updateSelectAllButtonState();
|
|
1407
|
+
if (this._config.debug) {
|
|
1408
|
+
console.log('Restored original options after search clear');
|
|
1409
|
+
}
|
|
1230
1410
|
};
|
|
1231
1411
|
/**
|
|
1232
1412
|
* Update search results in the dropdown
|
|
@@ -1235,31 +1415,24 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1235
1415
|
KTSelect.prototype._updateSearchResults = function (items) {
|
|
1236
1416
|
if (!this._dropdownContentElement)
|
|
1237
1417
|
return;
|
|
1238
|
-
|
|
1418
|
+
// Use cached options container for better performance
|
|
1419
|
+
var optionsContainer = this._optionsContainer ||
|
|
1420
|
+
this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
1239
1421
|
if (!optionsContainer)
|
|
1240
1422
|
return;
|
|
1241
|
-
//
|
|
1242
|
-
optionsContainer.innerHTML = '';
|
|
1423
|
+
// Handle empty results
|
|
1243
1424
|
if (items.length === 0) {
|
|
1244
|
-
|
|
1425
|
+
optionsContainer.innerHTML = '';
|
|
1245
1426
|
var noResultsElement = templates_1.defaultTemplates.searchEmpty(this._config);
|
|
1246
1427
|
optionsContainer.appendChild(noResultsElement);
|
|
1247
1428
|
return;
|
|
1248
1429
|
}
|
|
1249
|
-
//
|
|
1250
|
-
|
|
1251
|
-
// Create option for the original select
|
|
1252
|
-
var selectOption = document.createElement('option');
|
|
1253
|
-
selectOption.value = item.id;
|
|
1254
|
-
// Add to dropdown container
|
|
1255
|
-
optionsContainer.appendChild(selectOption);
|
|
1256
|
-
});
|
|
1430
|
+
// Use unified renderer for search results
|
|
1431
|
+
this._renderOptionsInDropdown(items, true);
|
|
1257
1432
|
// Add pagination "Load More" button if needed
|
|
1258
1433
|
if (this._config.pagination && this._remoteModule.hasMorePages()) {
|
|
1259
1434
|
this._addLoadMoreButton();
|
|
1260
1435
|
}
|
|
1261
|
-
// Update options NodeList
|
|
1262
|
-
this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
1263
1436
|
};
|
|
1264
1437
|
/**
|
|
1265
1438
|
* Check if dropdown is open
|
|
@@ -1271,10 +1444,12 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1271
1444
|
var _this = this;
|
|
1272
1445
|
var selectedValues = this.getSelectedOptions();
|
|
1273
1446
|
var displaySeparator = this._config.displaySeparator || ', ';
|
|
1274
|
-
var texts = selectedValues
|
|
1447
|
+
var texts = selectedValues
|
|
1448
|
+
.map(function (value) {
|
|
1275
1449
|
var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1276
1450
|
return (option === null || option === void 0 ? void 0 : option.getAttribute('data-text')) || '';
|
|
1277
|
-
})
|
|
1451
|
+
})
|
|
1452
|
+
.filter(Boolean);
|
|
1278
1453
|
return texts.join(displaySeparator);
|
|
1279
1454
|
};
|
|
1280
1455
|
/**
|
|
@@ -1282,7 +1457,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1282
1457
|
*/
|
|
1283
1458
|
KTSelect.prototype._isOptionDisabled = function (value) {
|
|
1284
1459
|
var dropdownOption = Array.from(this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1285
|
-
var isDropdownDisabled = dropdownOption &&
|
|
1460
|
+
var isDropdownDisabled = dropdownOption &&
|
|
1461
|
+
(dropdownOption.classList.contains('disabled') ||
|
|
1462
|
+
dropdownOption.getAttribute('aria-disabled') === 'true');
|
|
1286
1463
|
var selectOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
|
|
1287
1464
|
var isNativeDisabled = selectOption && selectOption.disabled;
|
|
1288
1465
|
return Boolean(isDropdownDisabled || isNativeDisabled);
|
|
@@ -1304,9 +1481,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1304
1481
|
if (event.target === this._searchInputElement) {
|
|
1305
1482
|
// Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
|
|
1306
1483
|
// For other keys (characters, space, backspace, delete), let the input field process them.
|
|
1307
|
-
if (event.key !== 'ArrowDown' &&
|
|
1308
|
-
event.key !== '
|
|
1309
|
-
event.key !== '
|
|
1484
|
+
if (event.key !== 'ArrowDown' &&
|
|
1485
|
+
event.key !== 'ArrowUp' &&
|
|
1486
|
+
event.key !== 'Escape' &&
|
|
1487
|
+
event.key !== 'Enter' &&
|
|
1488
|
+
event.key !== 'Tab' &&
|
|
1489
|
+
event.key !== 'Home' &&
|
|
1490
|
+
event.key !== 'End' &&
|
|
1491
|
+
event.key !== ' ') {
|
|
1310
1492
|
// If it's a character key and we are NOT type-to-searching (because search has focus)
|
|
1311
1493
|
// then let the input field handle it for its own value.
|
|
1312
1494
|
// The search module's 'input' event will handle filtering based on the input's value.
|
|
@@ -1320,7 +1502,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1320
1502
|
if (event.altKey || event.ctrlKey || event.metaKey)
|
|
1321
1503
|
return;
|
|
1322
1504
|
// Type-to-search: only for single char keys, when search input does not have focus
|
|
1323
|
-
if (event.key.length === 1 &&
|
|
1505
|
+
if (event.key.length === 1 &&
|
|
1506
|
+
!event.repeat &&
|
|
1507
|
+
!event.key.match(/\s/) &&
|
|
1508
|
+
document.activeElement !== this._searchInputElement) {
|
|
1324
1509
|
buffer.push(event.key);
|
|
1325
1510
|
var str = buffer.getBuffer();
|
|
1326
1511
|
if (isOpen) {
|
|
@@ -1369,7 +1554,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1369
1554
|
if (focusedOptionEl) {
|
|
1370
1555
|
var val = focusedOptionEl.dataset.value;
|
|
1371
1556
|
// If single select, and the item is already selected, just close.
|
|
1372
|
-
if (val !== undefined &&
|
|
1557
|
+
if (val !== undefined &&
|
|
1558
|
+
!this._config.multiple &&
|
|
1559
|
+
this._state.isSelected(val)) {
|
|
1373
1560
|
if (this._config.debug)
|
|
1374
1561
|
console.log('Enter on already selected item in single-select mode. Closing.');
|
|
1375
1562
|
this.closeDropdown();
|
|
@@ -1410,7 +1597,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1410
1597
|
var _this = this;
|
|
1411
1598
|
var optionsConfig = this._config.optionsConfig || {};
|
|
1412
1599
|
var displaySeparator = this._config.displaySeparator || ', ';
|
|
1413
|
-
var contentArray = Array.from(new Set(selectedValues
|
|
1600
|
+
var contentArray = Array.from(new Set(selectedValues
|
|
1601
|
+
.map(function (value) {
|
|
1414
1602
|
var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1415
1603
|
if (!option)
|
|
1416
1604
|
return '';
|
|
@@ -1419,7 +1607,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1419
1607
|
// Replace all {{varname}} in option.innerHTML with values from _config
|
|
1420
1608
|
Object.entries(optionsConfig[value] || {}).forEach(function (_a) {
|
|
1421
1609
|
var key = _a[0], val = _a[1];
|
|
1422
|
-
if ([
|
|
1610
|
+
if (['string', 'number', 'boolean'].includes(typeof val)) {
|
|
1423
1611
|
displayTemplate = displayTemplate.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
|
|
1424
1612
|
}
|
|
1425
1613
|
});
|
|
@@ -1428,7 +1616,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1428
1616
|
selectedTexts: _this.getSelectedOptionsText() || '',
|
|
1429
1617
|
text: text,
|
|
1430
1618
|
});
|
|
1431
|
-
})
|
|
1619
|
+
})
|
|
1620
|
+
.filter(Boolean)));
|
|
1432
1621
|
return contentArray.join(displaySeparator);
|
|
1433
1622
|
};
|
|
1434
1623
|
KTSelect.prototype.getDisplayElement = function () {
|
|
@@ -1447,7 +1636,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1447
1636
|
// Option(s) added or removed
|
|
1448
1637
|
needsRebuild = true;
|
|
1449
1638
|
}
|
|
1450
|
-
else if (mutation.type === 'attributes' &&
|
|
1639
|
+
else if (mutation.type === 'attributes' &&
|
|
1640
|
+
mutation.target instanceof HTMLOptionElement) {
|
|
1451
1641
|
if (mutation.attributeName === 'selected') {
|
|
1452
1642
|
needsSelectionSync = true;
|
|
1453
1643
|
}
|
|
@@ -1500,6 +1690,57 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1500
1690
|
this._state.setSelectedOptions(this._config.multiple ? selected : selected[0] || '');
|
|
1501
1691
|
this.updateSelectedOptionDisplay();
|
|
1502
1692
|
this._updateSelectedOptionClass();
|
|
1693
|
+
this.updateSelectAllButtonState();
|
|
1694
|
+
};
|
|
1695
|
+
KTSelect.prototype._handleSelectAllClick = function (event) {
|
|
1696
|
+
event.preventDefault();
|
|
1697
|
+
event.stopPropagation();
|
|
1698
|
+
var visibleOptions = this._focusManager
|
|
1699
|
+
.getVisibleOptions()
|
|
1700
|
+
.filter(function (opt) { return opt.getAttribute('aria-disabled') !== 'true'; });
|
|
1701
|
+
if (visibleOptions.length === 0)
|
|
1702
|
+
return;
|
|
1703
|
+
var visibleValues = visibleOptions.map(function (opt) { return opt.dataset.value; });
|
|
1704
|
+
var selectedValues = new Set(this.getSelectedOptions());
|
|
1705
|
+
var isAllSelected = visibleOptions.every(function (opt) {
|
|
1706
|
+
return selectedValues.has(opt.dataset.value);
|
|
1707
|
+
});
|
|
1708
|
+
if (isAllSelected) {
|
|
1709
|
+
// Deselect all visible
|
|
1710
|
+
visibleValues.forEach(function (value) { return selectedValues.delete(value); });
|
|
1711
|
+
}
|
|
1712
|
+
else {
|
|
1713
|
+
// Select all visible
|
|
1714
|
+
visibleValues.forEach(function (value) { return selectedValues.add(value); });
|
|
1715
|
+
}
|
|
1716
|
+
this._state.setSelectedOptions(Array.from(selectedValues));
|
|
1717
|
+
this.updateSelectedOptionDisplay();
|
|
1718
|
+
this._updateSelectedOptionClass();
|
|
1719
|
+
this.updateSelectAllButtonState();
|
|
1720
|
+
this._dispatchEvent('change');
|
|
1721
|
+
this._fireEvent('change');
|
|
1722
|
+
};
|
|
1723
|
+
KTSelect.prototype.updateSelectAllButtonState = function () {
|
|
1724
|
+
if (!this._config.multiple ||
|
|
1725
|
+
!this._config.enableSelectAll ||
|
|
1726
|
+
!this._selectAllButtonToggle) {
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
var visibleOptions = this._focusManager
|
|
1730
|
+
.getVisibleOptions()
|
|
1731
|
+
.filter(function (opt) { return opt.getAttribute('aria-disabled') !== 'true'; });
|
|
1732
|
+
if (visibleOptions.length === 0) {
|
|
1733
|
+
this._selectAllButton.style.display = 'none';
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
this._selectAllButton.style.display = '';
|
|
1737
|
+
var selectedValues = new Set(this.getSelectedOptions());
|
|
1738
|
+
var isAllSelected = visibleOptions.every(function (opt) {
|
|
1739
|
+
return selectedValues.has(opt.dataset.value);
|
|
1740
|
+
});
|
|
1741
|
+
this._selectAllButtonToggle.textContent = isAllSelected
|
|
1742
|
+
? this._config.clearAllText
|
|
1743
|
+
: this._config.selectAllText;
|
|
1503
1744
|
};
|
|
1504
1745
|
/**
|
|
1505
1746
|
* ========================================================================
|