@keenthemes/ktui 1.0.25 → 1.0.27
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 +335 -36
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +216 -13
- package/examples/datatable/checkbox-events-test.html +400 -0
- package/examples/datatable/credentials-test.html +423 -0
- package/examples/datatable/remote-checkbox-test.html +365 -0
- package/examples/modal/persistent.html +205 -0
- package/examples/modal/remote-select-dropdown.html +166 -0
- package/examples/modal/select-dropdown-container.html +129 -0
- package/examples/select/formdata-remote.html +161 -0
- package/examples/select/modal-positioning-test.html +338 -0
- package/lib/cjs/components/datatable/datatable-checkbox.js +16 -3
- package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +3 -5
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/image-input/image-input.js.map +1 -1
- package/lib/cjs/components/modal/modal.js +16 -2
- package/lib/cjs/components/modal/modal.js.map +1 -1
- package/lib/cjs/components/select/config.js +5 -0
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +54 -3
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/select.js +241 -23
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/esm/components/datatable/datatable-checkbox.js +16 -3
- package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +3 -5
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/image-input/image-input.js.map +1 -1
- package/lib/esm/components/modal/modal.js +16 -2
- package/lib/esm/components/modal/modal.js.map +1 -1
- package/lib/esm/components/select/config.js +5 -0
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +54 -3
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/select.js +241 -23
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/templates.js.map +1 -1
- package/package.json +1 -1
- package/src/components/datatable/datatable-checkbox.ts +18 -3
- package/src/components/datatable/datatable.ts +3 -0
- package/src/components/datatable/types.ts +1 -0
- package/src/components/image-input/image-input.ts +12 -15
- package/src/components/modal/modal.ts +20 -2
- package/src/components/select/config.ts +6 -0
- package/src/components/select/dropdown.ts +69 -4
- package/src/components/select/select.ts +306 -36
- package/src/components/select/templates.ts +2 -1
- package/lib/cjs/components/config.js +0 -26
- package/lib/cjs/components/config.js.map +0 -1
- package/lib/cjs/components/config.umd.js +0 -23
- package/lib/cjs/components/config.umd.js.map +0 -1
- package/lib/cjs/components/menu/index.js +0 -6
- package/lib/cjs/components/menu/index.js.map +0 -1
- package/lib/cjs/components/menu/menu.js +0 -1021
- package/lib/cjs/components/menu/menu.js.map +0 -1
- package/lib/cjs/components/menu/types.js +0 -3
- package/lib/cjs/components/menu/types.js.map +0 -1
- package/lib/cjs/components/theme/index.js +0 -6
- package/lib/cjs/components/theme/index.js.map +0 -1
- package/lib/cjs/components/theme/theme.js +0 -147
- package/lib/cjs/components/theme/theme.js.map +0 -1
- package/lib/cjs/components/theme/types.js +0 -3
- package/lib/cjs/components/theme/types.js.map +0 -1
- package/lib/esm/components/config.js +0 -24
- package/lib/esm/components/config.js.map +0 -1
- package/lib/esm/components/config.umd.js +0 -23
- package/lib/esm/components/config.umd.js.map +0 -1
- package/lib/esm/components/menu/index.js +0 -2
- package/lib/esm/components/menu/index.js.map +0 -1
- package/lib/esm/components/menu/menu.js +0 -1018
- package/lib/esm/components/menu/menu.js.map +0 -1
- package/lib/esm/components/menu/types.js +0 -2
- package/lib/esm/components/menu/types.js.map +0 -1
- package/lib/esm/components/theme/index.js +0 -2
- package/lib/esm/components/theme/index.js.map +0 -1
- package/lib/esm/components/theme/theme.js +0 -144
- package/lib/esm/components/theme/theme.js.map +0 -1
- package/lib/esm/components/theme/types.js +0 -2
- package/lib/esm/components/theme/types.js.map +0 -1
- /package/examples/select/{dark-mode-test.html → dark-mode.html} +0 -0
- /package/examples/select/{dropdowncontainer-test.html → dropdowncontainer.html} +0 -0
- /package/examples/select/{global-config-test.html → global-config.html} +0 -0
package/dist/ktui.js
CHANGED
|
@@ -6993,8 +6993,11 @@ function createCheckboxHandler(element, config, fireEvent) {
|
|
|
6993
6993
|
return;
|
|
6994
6994
|
var value = input.value;
|
|
6995
6995
|
var selectedRows = getSelectedRows();
|
|
6996
|
-
|
|
6997
|
-
|
|
6996
|
+
var wasChecked = selectedRows.includes(value);
|
|
6997
|
+
var isNowChecked = input.checked;
|
|
6998
|
+
// Update state first
|
|
6999
|
+
if (isNowChecked) {
|
|
7000
|
+
if (!wasChecked)
|
|
6998
7001
|
selectedRows.push(value);
|
|
6999
7002
|
}
|
|
7000
7003
|
else {
|
|
@@ -7002,14 +7005,24 @@ function createCheckboxHandler(element, config, fireEvent) {
|
|
|
7002
7005
|
}
|
|
7003
7006
|
setSelectedRows(selectedRows);
|
|
7004
7007
|
updateHeaderCheckboxState();
|
|
7008
|
+
// Fire specific checked/unchecked events after state is updated
|
|
7009
|
+
if (isNowChecked && !wasChecked) {
|
|
7010
|
+
fireEvent('checked');
|
|
7011
|
+
}
|
|
7012
|
+
else if (!isNowChecked && wasChecked) {
|
|
7013
|
+
fireEvent('unchecked');
|
|
7014
|
+
}
|
|
7015
|
+
// Always fire changed event for backward compatibility
|
|
7005
7016
|
fireEvent('changed');
|
|
7006
7017
|
}
|
|
7007
7018
|
// When the header checkbox is toggled
|
|
7008
7019
|
function checkboxToggle(event) {
|
|
7009
7020
|
var checked = !isChecked();
|
|
7021
|
+
// Update state first, then fire events
|
|
7022
|
+
change(checked);
|
|
7023
|
+
// Fire checked/unchecked events after state is updated
|
|
7010
7024
|
var eventType = checked ? 'checked' : 'unchecked';
|
|
7011
7025
|
fireEvent(eventType);
|
|
7012
|
-
change(checked);
|
|
7013
7026
|
}
|
|
7014
7027
|
// Change all visible checkboxes and update selectedRows
|
|
7015
7028
|
function change(checked) {
|
|
@@ -8405,11 +8418,9 @@ var KTDataTable = /** @class */ (function (_super) {
|
|
|
8405
8418
|
apiEndpointWithQueryParams.search = queryParams.toString();
|
|
8406
8419
|
this._config.apiEndpoint = apiEndpointWithQueryParams.toString();
|
|
8407
8420
|
}
|
|
8408
|
-
return [2 /*return*/, fetch(this._config.apiEndpoint, {
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
headers: this._config.requestHeaders,
|
|
8412
|
-
}).catch(function (error) {
|
|
8421
|
+
return [2 /*return*/, fetch(this._config.apiEndpoint, __assign({ method: requestMethod, body: requestBody, headers: this._config.requestHeaders }, (this._config.requestCredentials && {
|
|
8422
|
+
credentials: this._config.requestCredentials,
|
|
8423
|
+
}))).catch(function (error) {
|
|
8413
8424
|
// Trigger an error event
|
|
8414
8425
|
_this._fireEvent('error', { error: error });
|
|
8415
8426
|
_this._dispatchEvent('error', { error: error });
|
|
@@ -9241,9 +9252,23 @@ var KTModal = /** @class */ (function (_super) {
|
|
|
9241
9252
|
KTModal.prototype._handlers = function () {
|
|
9242
9253
|
var _this = this;
|
|
9243
9254
|
this._element.addEventListener('click', function (event) {
|
|
9244
|
-
|
|
9255
|
+
var target = event.target;
|
|
9256
|
+
var currentTarget = event.currentTarget;
|
|
9257
|
+
// Only proceed if clicking directly on the backdrop (modal element itself)
|
|
9258
|
+
// This prevents closing when clicking inside modal content or any child elements
|
|
9259
|
+
// (including dropdowns rendered via dropdownContainer pointing to modal)
|
|
9260
|
+
if (target !== currentTarget) {
|
|
9261
|
+
// Stop propagation for clicks inside dropdowns to prevent dropdown from closing
|
|
9262
|
+
// Check if click is inside a dropdown element (KT Select dropdown)
|
|
9263
|
+
var dropdownElement = target.closest('[data-kt-select-dropdown]');
|
|
9264
|
+
if (dropdownElement) {
|
|
9265
|
+
event.stopPropagation();
|
|
9266
|
+
}
|
|
9245
9267
|
return;
|
|
9246
|
-
|
|
9268
|
+
}
|
|
9269
|
+
// Only hide if both backdropStatic is false AND persistent is false
|
|
9270
|
+
if (_this._getOption('backdropStatic') === false &&
|
|
9271
|
+
utils_1.default.stringToBoolean(_this._getOption('persistent')) === false) {
|
|
9247
9272
|
_this._hide();
|
|
9248
9273
|
}
|
|
9249
9274
|
});
|
|
@@ -9563,8 +9588,14 @@ var KTSelectDropdown = /** @class */ (function (_super) {
|
|
|
9563
9588
|
_this._dropdownElement = dropdownElement;
|
|
9564
9589
|
_this._config = config;
|
|
9565
9590
|
_this._ktSelectInstance = ktSelectInstance; // Assign instance
|
|
9591
|
+
// For centered modals, don't move dropdown to container to preserve positioning context
|
|
9592
|
+
// For other cases, move to container if specified
|
|
9593
|
+
var modalParent = _this._getModalContainer();
|
|
9594
|
+
var isCenteredModal = modalParent && modalParent.classList.contains('kt-modal-center');
|
|
9595
|
+
// Only move dropdown if not in centered modal (regardless of strategy override)
|
|
9596
|
+
// This prevents the positioning bug even if user sets dropdownStrategy: 'fixed'
|
|
9566
9597
|
var container = _this._resolveDropdownContainer();
|
|
9567
|
-
if (container) {
|
|
9598
|
+
if (container && !isCenteredModal) {
|
|
9568
9599
|
if (container !== _this._dropdownElement.parentElement) {
|
|
9569
9600
|
container.appendChild(_this._dropdownElement);
|
|
9570
9601
|
}
|
|
@@ -9632,6 +9663,49 @@ var KTSelectDropdown = /** @class */ (function (_super) {
|
|
|
9632
9663
|
this._dropdownElement.style.width = "".concat(toggleWidth, "px");
|
|
9633
9664
|
}
|
|
9634
9665
|
};
|
|
9666
|
+
/**
|
|
9667
|
+
* Detect if the select is inside a modal container
|
|
9668
|
+
* @returns The modal element if found, null otherwise
|
|
9669
|
+
*/
|
|
9670
|
+
KTSelectDropdown.prototype._getModalContainer = function () {
|
|
9671
|
+
return this._element.closest('[data-kt-modal], .kt-modal, .kt-modal-center');
|
|
9672
|
+
};
|
|
9673
|
+
/**
|
|
9674
|
+
* Get the appropriate boundary element for Popper positioning
|
|
9675
|
+
* For centered modals, use .kt-modal-content to avoid transform calculation issues
|
|
9676
|
+
* @returns The boundary element, or null if no modal found
|
|
9677
|
+
*/
|
|
9678
|
+
KTSelectDropdown.prototype._getModalBoundary = function () {
|
|
9679
|
+
var modalParent = this._getModalContainer();
|
|
9680
|
+
if (!modalParent) {
|
|
9681
|
+
return null;
|
|
9682
|
+
}
|
|
9683
|
+
// For centered modals, use .kt-modal-content as boundary to avoid transform issues
|
|
9684
|
+
if (modalParent.classList.contains('kt-modal-center')) {
|
|
9685
|
+
var modalContent = modalParent.querySelector('.kt-modal-content');
|
|
9686
|
+
return modalContent || modalParent;
|
|
9687
|
+
}
|
|
9688
|
+
// For non-centered modals, use the modal element itself
|
|
9689
|
+
return modalParent;
|
|
9690
|
+
};
|
|
9691
|
+
/**
|
|
9692
|
+
* Get the appropriate positioning strategy based on context
|
|
9693
|
+
* @returns 'fixed' if inside non-centered modal, 'absolute' for centered modals or no modal
|
|
9694
|
+
*/
|
|
9695
|
+
KTSelectDropdown.prototype._getPositioningStrategy = function () {
|
|
9696
|
+
// Check if config explicitly sets strategy
|
|
9697
|
+
if (this._config.dropdownStrategy) {
|
|
9698
|
+
return this._config.dropdownStrategy;
|
|
9699
|
+
}
|
|
9700
|
+
// For centered modals, use absolute positioning to avoid transform calculation issues
|
|
9701
|
+
// For non-centered modals, use fixed positioning
|
|
9702
|
+
var modalParent = this._getModalContainer();
|
|
9703
|
+
if (modalParent && modalParent.classList.contains('kt-modal-center')) {
|
|
9704
|
+
return 'absolute';
|
|
9705
|
+
}
|
|
9706
|
+
// Use fixed positioning for non-centered modals
|
|
9707
|
+
return modalParent ? 'fixed' : 'absolute';
|
|
9708
|
+
};
|
|
9635
9709
|
/**
|
|
9636
9710
|
* Initialize the Popper instance for dropdown positioning
|
|
9637
9711
|
*/
|
|
@@ -9642,9 +9716,11 @@ var KTSelectDropdown = /** @class */ (function (_super) {
|
|
|
9642
9716
|
var offsetValue = '0, 5';
|
|
9643
9717
|
// Get configuration options
|
|
9644
9718
|
var placement = this._config.dropdownPlacement || 'bottom-start';
|
|
9645
|
-
var strategy = this.
|
|
9719
|
+
var strategy = this._getPositioningStrategy();
|
|
9646
9720
|
var preventOverflow = this._config.dropdownPreventOverflow !== false;
|
|
9647
9721
|
var flip = this._config.dropdownFlip !== false;
|
|
9722
|
+
// Get appropriate boundary element for modal context
|
|
9723
|
+
var boundary = this._getModalBoundary() || 'clippingParents';
|
|
9648
9724
|
// Create new popper instance
|
|
9649
9725
|
this._popperInstance = (0, core_1.createPopper)(this._toggleElement, this._dropdownElement, {
|
|
9650
9726
|
placement: placement,
|
|
@@ -9659,7 +9735,7 @@ var KTSelectDropdown = /** @class */ (function (_super) {
|
|
|
9659
9735
|
{
|
|
9660
9736
|
name: 'preventOverflow',
|
|
9661
9737
|
options: {
|
|
9662
|
-
boundary:
|
|
9738
|
+
boundary: boundary,
|
|
9663
9739
|
altAxis: preventOverflow,
|
|
9664
9740
|
},
|
|
9665
9741
|
},
|
|
@@ -11858,6 +11934,12 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
11858
11934
|
KTSelect.prototype._completeRemoteSetup = function () {
|
|
11859
11935
|
// Initialize options
|
|
11860
11936
|
this._preSelectOptions(this._element);
|
|
11937
|
+
// Prevent browser auto-selection when placeholder is configured
|
|
11938
|
+
if (this._config.placeholder &&
|
|
11939
|
+
this._state.getSelectedOptions().length === 0 &&
|
|
11940
|
+
this._preSelectedValues.length === 0) {
|
|
11941
|
+
this._element.value = '';
|
|
11942
|
+
}
|
|
11861
11943
|
// Apply pre-selected values captured before remote data was loaded
|
|
11862
11944
|
if (this._preSelectedValues.length > 0) {
|
|
11863
11945
|
if (this._config.debug) {
|
|
@@ -12100,6 +12182,11 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
12100
12182
|
this._setupElementReferences();
|
|
12101
12183
|
// Initialize options
|
|
12102
12184
|
this._preSelectOptions(this._element);
|
|
12185
|
+
// Prevent browser auto-selection when placeholder is configured
|
|
12186
|
+
if (this._config.placeholder &&
|
|
12187
|
+
this._state.getSelectedOptions().length === 0) {
|
|
12188
|
+
this._element.value = '';
|
|
12189
|
+
}
|
|
12103
12190
|
// Apply disabled state if needed
|
|
12104
12191
|
this._applyInitialDisabledState();
|
|
12105
12192
|
// Initialize search if enabled
|
|
@@ -12533,6 +12620,22 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
12533
12620
|
selectedOptions: this.getSelectedOptions(),
|
|
12534
12621
|
});
|
|
12535
12622
|
};
|
|
12623
|
+
/**
|
|
12624
|
+
* Sync native select value attribute for FormData support
|
|
12625
|
+
*/
|
|
12626
|
+
KTSelect.prototype._syncNativeSelectValue = function () {
|
|
12627
|
+
var selectedOptions = this.getSelectedOptions();
|
|
12628
|
+
if (this._config.multiple) {
|
|
12629
|
+
// For multiple select, the selected options are marked via option.selected
|
|
12630
|
+
// The native select's value property will return the first selected option's value
|
|
12631
|
+
// FormData will include all selected values automatically
|
|
12632
|
+
}
|
|
12633
|
+
else {
|
|
12634
|
+
// For single select, set the value attribute explicitly
|
|
12635
|
+
var selectedValue = selectedOptions.length > 0 ? selectedOptions[0] : '';
|
|
12636
|
+
this._element.value = selectedValue;
|
|
12637
|
+
}
|
|
12638
|
+
};
|
|
12536
12639
|
/**
|
|
12537
12640
|
* Update selected option display value
|
|
12538
12641
|
*/
|
|
@@ -12540,6 +12643,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
12540
12643
|
var selectedOptions = this.getSelectedOptions();
|
|
12541
12644
|
var tagsEnabled = this._config.tags && this._tagsModule;
|
|
12542
12645
|
var valueDisplayEl = this.getValueDisplayElement();
|
|
12646
|
+
// Sync native select value for FormData support
|
|
12647
|
+
this._syncNativeSelectValue();
|
|
12543
12648
|
if (tagsEnabled) {
|
|
12544
12649
|
// Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
|
|
12545
12650
|
this._tagsModule.updateTagsDisplay(selectedOptions);
|
|
@@ -12641,6 +12746,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
12641
12746
|
Array.from(this._element.querySelectorAll('option')).forEach(function (opt) {
|
|
12642
12747
|
opt.selected = false;
|
|
12643
12748
|
});
|
|
12749
|
+
// Clear native select value
|
|
12750
|
+
this._element.value = '';
|
|
12644
12751
|
this.updateSelectedOptionDisplay();
|
|
12645
12752
|
this._updateSelectedOptionClass();
|
|
12646
12753
|
// Update select all button state
|
|
@@ -13009,41 +13116,228 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
13009
13116
|
};
|
|
13010
13117
|
/**
|
|
13011
13118
|
* Update the dropdown to sync with native select element changes
|
|
13012
|
-
*
|
|
13013
|
-
*
|
|
13119
|
+
* For remote selects, refetches data from the server and preserves selections
|
|
13120
|
+
* Optionally accepts new options to replace existing ones (static selects only)
|
|
13121
|
+
*
|
|
13122
|
+
* @param newOptions Optional array of new options [{value, text}, ...] (static selects only)
|
|
13014
13123
|
* @public
|
|
13124
|
+
* @remarks
|
|
13125
|
+
* - For static selects: rebuilds dropdown from native select or new options
|
|
13126
|
+
* - For remote selects: fetches fresh data, preserves matching selections
|
|
13127
|
+
* - Selections are preserved if their values exist in new remote data
|
|
13128
|
+
* - Selections are cleared if their values don't exist in new data
|
|
13129
|
+
* @fires updated - After update completes successfully
|
|
13130
|
+
* @fires updateError - If remote data fetch fails
|
|
13015
13131
|
*/
|
|
13016
13132
|
KTSelect.prototype.update = function (newOptions) {
|
|
13017
13133
|
var _this = this;
|
|
13018
|
-
|
|
13019
|
-
|
|
13020
|
-
this.
|
|
13021
|
-
|
|
13022
|
-
|
|
13023
|
-
|
|
13024
|
-
|
|
13025
|
-
|
|
13026
|
-
_this.
|
|
13134
|
+
// For remote selects, refetch data
|
|
13135
|
+
if (this._config.remote && this._remoteModule) {
|
|
13136
|
+
this._remoteModule
|
|
13137
|
+
.fetchData()
|
|
13138
|
+
.then(function (items) {
|
|
13139
|
+
// Capture currently selected values before clearing
|
|
13140
|
+
var currentlySelected = _this._state.getSelectedOptions();
|
|
13141
|
+
// Clear existing options (also captures to _preSelectedValues)
|
|
13142
|
+
_this._clearExistingOptions();
|
|
13143
|
+
// Get all available values from new remote data
|
|
13144
|
+
var availableValues = items.map(function (item) { return item.id; });
|
|
13145
|
+
// Filter to only values that exist in new data
|
|
13146
|
+
var validSelections = currentlySelected.filter(function (value) {
|
|
13147
|
+
return availableValues.includes(value);
|
|
13148
|
+
});
|
|
13149
|
+
if (_this._config.debug && currentlySelected.length > 0) {
|
|
13150
|
+
console.log('update(): Preserving selections that exist in new data:', validSelections);
|
|
13151
|
+
}
|
|
13152
|
+
// Add new options from remote data and restore selection state
|
|
13153
|
+
items.forEach(function (item) {
|
|
13154
|
+
var option = document.createElement('option');
|
|
13155
|
+
option.value = item.id;
|
|
13156
|
+
option.textContent = item.title;
|
|
13157
|
+
if (item.disabled)
|
|
13158
|
+
option.disabled = true;
|
|
13159
|
+
// Restore selected attribute for preserved selections
|
|
13160
|
+
if (validSelections.includes(item.id)) {
|
|
13161
|
+
option.selected = true;
|
|
13162
|
+
}
|
|
13163
|
+
_this._element.appendChild(option);
|
|
13164
|
+
});
|
|
13165
|
+
// Rebuild dropdown
|
|
13166
|
+
_this._rebuildOptionsFromNative();
|
|
13167
|
+
// Sync selection state from native select (now has selected attributes)
|
|
13168
|
+
_this._syncSelectionFromNative();
|
|
13169
|
+
// Dispatch updated event
|
|
13170
|
+
_this._dispatchEvent('updated');
|
|
13171
|
+
_this._fireEvent('updated');
|
|
13172
|
+
})
|
|
13173
|
+
.catch(function (error) {
|
|
13174
|
+
console.error('Error updating remote data:', error);
|
|
13175
|
+
_this._dispatchEvent('updateError');
|
|
13176
|
+
_this._fireEvent('updateError');
|
|
13027
13177
|
});
|
|
13028
13178
|
}
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13179
|
+
else {
|
|
13180
|
+
// For static selects, handle new options
|
|
13181
|
+
if (newOptions) {
|
|
13182
|
+
// Clear existing options except placeholder
|
|
13183
|
+
this._clearExistingOptions();
|
|
13184
|
+
// Add new options to native select
|
|
13185
|
+
newOptions.forEach(function (opt) {
|
|
13186
|
+
var option = document.createElement('option');
|
|
13187
|
+
option.value = opt.value;
|
|
13188
|
+
option.textContent = opt.text;
|
|
13189
|
+
_this._element.appendChild(option);
|
|
13190
|
+
});
|
|
13191
|
+
}
|
|
13192
|
+
// Rebuild dropdown from native select
|
|
13193
|
+
this._rebuildOptionsFromNative();
|
|
13194
|
+
// Dispatch updated event
|
|
13195
|
+
this._dispatchEvent('updated');
|
|
13196
|
+
this._fireEvent('updated');
|
|
13197
|
+
}
|
|
13198
|
+
};
|
|
13199
|
+
/**
|
|
13200
|
+
* Reload remote data and rebuild the dropdown
|
|
13201
|
+
* Only works with remote data enabled
|
|
13202
|
+
* @returns Promise that resolves when reload completes
|
|
13203
|
+
* @public
|
|
13204
|
+
*/
|
|
13205
|
+
KTSelect.prototype.reload = function () {
|
|
13206
|
+
var _this = this;
|
|
13207
|
+
// Guard clause: only works with remote data
|
|
13208
|
+
if (!this._config.remote || !this._remoteModule) {
|
|
13209
|
+
console.warn('reload() only works with remote data enabled');
|
|
13210
|
+
return Promise.resolve();
|
|
13211
|
+
}
|
|
13212
|
+
// Dispatch reload start event
|
|
13213
|
+
this._dispatchEvent('reloadStart');
|
|
13214
|
+
this._fireEvent('reloadStart');
|
|
13215
|
+
// Capture currently selected values before clearing
|
|
13216
|
+
var currentlySelected = this._state.getSelectedOptions();
|
|
13217
|
+
// Fetch fresh remote data
|
|
13218
|
+
return this._remoteModule
|
|
13219
|
+
.fetchData()
|
|
13220
|
+
.then(function (items) {
|
|
13221
|
+
// Clear existing options (captures to _preSelectedValues)
|
|
13222
|
+
_this._clearExistingOptions();
|
|
13223
|
+
// Update state with new items
|
|
13224
|
+
return _this._state.setItems(items).then(function () {
|
|
13225
|
+
// Generate new options HTML
|
|
13226
|
+
_this._generateOptionsHtml(_this._element);
|
|
13227
|
+
// Preserve selections by marking matching options as selected
|
|
13228
|
+
var availableValues = items.map(function (item) {
|
|
13229
|
+
return item.id !== undefined ? String(item.id) : '';
|
|
13230
|
+
});
|
|
13231
|
+
var validSelections = currentlySelected.filter(function (value) {
|
|
13232
|
+
return availableValues.includes(value);
|
|
13233
|
+
});
|
|
13234
|
+
if (_this._config.debug && currentlySelected.length > 0) {
|
|
13235
|
+
console.log('reload(): Preserving selections that exist in new data:', validSelections);
|
|
13236
|
+
}
|
|
13237
|
+
// Mark preserved selections on new options
|
|
13238
|
+
validSelections.forEach(function (value) {
|
|
13239
|
+
var option = Array.from(_this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
|
|
13240
|
+
if (option) {
|
|
13241
|
+
option.selected = true;
|
|
13242
|
+
}
|
|
13243
|
+
});
|
|
13244
|
+
// Update the dropdown
|
|
13245
|
+
_this._updateDropdownWithNewOptions();
|
|
13246
|
+
// Sync selection state from native select (now has selected attributes)
|
|
13247
|
+
_this._syncSelectionFromNative();
|
|
13248
|
+
// Update visual display
|
|
13249
|
+
_this.updateSelectedOptionDisplay();
|
|
13250
|
+
_this._updateSelectedOptionClass();
|
|
13251
|
+
// Update select all button state if applicable
|
|
13252
|
+
if (_this._config.multiple && _this._config.enableSelectAll) {
|
|
13253
|
+
_this.updateSelectAllButtonState();
|
|
13254
|
+
}
|
|
13255
|
+
// Dispatch reload complete event
|
|
13256
|
+
_this._dispatchEvent('reloadComplete');
|
|
13257
|
+
_this._fireEvent('reloadComplete');
|
|
13258
|
+
});
|
|
13259
|
+
})
|
|
13260
|
+
.catch(function (error) {
|
|
13261
|
+
console.error('Error reloading remote data:', error);
|
|
13262
|
+
// Dispatch reload error event with error details
|
|
13263
|
+
_this._dispatchEvent('reloadError', { error: error });
|
|
13264
|
+
_this._fireEvent('reloadError', { error: error });
|
|
13265
|
+
// Re-throw error so caller can handle it
|
|
13266
|
+
throw error;
|
|
13267
|
+
});
|
|
13034
13268
|
};
|
|
13035
13269
|
/**
|
|
13036
13270
|
* Refresh the visual display and state without rebuilding options
|
|
13271
|
+
* For remote selects, refetches data from the server and preserves selections
|
|
13272
|
+
* that exist in the newly fetched data
|
|
13273
|
+
*
|
|
13037
13274
|
* @public
|
|
13275
|
+
* @remarks
|
|
13276
|
+
* - For static selects: syncs visual state with native select
|
|
13277
|
+
* - For remote selects: fetches fresh data, preserves matching selections
|
|
13278
|
+
* - Selections are preserved if their values exist in new remote data
|
|
13279
|
+
* - Selections are cleared if their values don't exist in new data
|
|
13280
|
+
* @fires refreshed - After refresh completes successfully
|
|
13281
|
+
* @fires refreshError - If remote data fetch fails
|
|
13038
13282
|
*/
|
|
13039
13283
|
KTSelect.prototype.refresh = function () {
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13284
|
+
var _this = this;
|
|
13285
|
+
// For remote selects, refetch data
|
|
13286
|
+
if (this._config.remote && this._remoteModule) {
|
|
13287
|
+
this._remoteModule
|
|
13288
|
+
.fetchData()
|
|
13289
|
+
.then(function (items) {
|
|
13290
|
+
// Capture currently selected values before clearing
|
|
13291
|
+
var currentlySelected = _this._state.getSelectedOptions();
|
|
13292
|
+
// Clear existing options (also captures to _preSelectedValues)
|
|
13293
|
+
_this._clearExistingOptions();
|
|
13294
|
+
// Get all available values from new remote data
|
|
13295
|
+
var availableValues = items.map(function (item) { return item.id; });
|
|
13296
|
+
// Filter to only values that exist in new data
|
|
13297
|
+
var validSelections = currentlySelected.filter(function (value) {
|
|
13298
|
+
return availableValues.includes(value);
|
|
13299
|
+
});
|
|
13300
|
+
if (_this._config.debug && currentlySelected.length > 0) {
|
|
13301
|
+
console.log('refresh(): Preserving selections that exist in new data:', validSelections);
|
|
13302
|
+
}
|
|
13303
|
+
// Add new options and restore selection state
|
|
13304
|
+
items.forEach(function (item) {
|
|
13305
|
+
var option = document.createElement('option');
|
|
13306
|
+
option.value = item.id;
|
|
13307
|
+
option.textContent = item.title;
|
|
13308
|
+
if (item.disabled)
|
|
13309
|
+
option.disabled = true;
|
|
13310
|
+
// Restore selected attribute for preserved selections
|
|
13311
|
+
if (validSelections.includes(item.id)) {
|
|
13312
|
+
option.selected = true;
|
|
13313
|
+
}
|
|
13314
|
+
_this._element.appendChild(option);
|
|
13315
|
+
});
|
|
13316
|
+
// Rebuild dropdown
|
|
13317
|
+
_this._rebuildOptionsFromNative();
|
|
13318
|
+
// Sync selection state from native select (now has selected attributes)
|
|
13319
|
+
_this._syncSelectionFromNative();
|
|
13320
|
+
// Reapply ARIA attributes
|
|
13321
|
+
_this._setAriaAttributes();
|
|
13322
|
+
// Dispatch refreshed event
|
|
13323
|
+
_this._dispatchEvent('refreshed');
|
|
13324
|
+
_this._fireEvent('refreshed');
|
|
13325
|
+
})
|
|
13326
|
+
.catch(function (error) {
|
|
13327
|
+
console.error('Error refreshing remote data:', error);
|
|
13328
|
+
_this._dispatchEvent('refreshError');
|
|
13329
|
+
_this._fireEvent('refreshError');
|
|
13330
|
+
});
|
|
13331
|
+
}
|
|
13332
|
+
else {
|
|
13333
|
+
// For static selects, just sync visual state
|
|
13334
|
+
this._syncSelectionFromNative();
|
|
13335
|
+
// Reapply ARIA attributes
|
|
13336
|
+
this._setAriaAttributes();
|
|
13337
|
+
// Dispatch refreshed event
|
|
13338
|
+
this._dispatchEvent('refreshed');
|
|
13339
|
+
this._fireEvent('refreshed');
|
|
13340
|
+
}
|
|
13047
13341
|
};
|
|
13048
13342
|
/**
|
|
13049
13343
|
* ========================================================================
|
|
@@ -18447,6 +18741,11 @@ var KTSelectState = /** @class */ (function () {
|
|
|
18447
18741
|
return this._config;
|
|
18448
18742
|
};
|
|
18449
18743
|
KTSelectState.prototype.setSelectedOptions = function (value) {
|
|
18744
|
+
// Handle empty array case first to prevent undefined elements
|
|
18745
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
18746
|
+
this._selectedOptions = [];
|
|
18747
|
+
return;
|
|
18748
|
+
}
|
|
18450
18749
|
if (this._config.multiple &&
|
|
18451
18750
|
typeof value === 'string' &&
|
|
18452
18751
|
!this._selectedOptions.includes(value)) {
|