UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

808 lines (805 loc) • 31.5 kB
/** * DevExtreme (cjs/__internal/ui/m_select_box.js) * Version: 24.2.6 * Build date: Mon Mar 17 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; require("../ui/list/modules/m_selection"); var _index = require("../../common/core/events/utils/index"); var _message = _interopRequireDefault(require("../../common/core/localization/message")); var _component_registrator = _interopRequireDefault(require("../../core/component_registrator")); var _dom_adapter = _interopRequireDefault(require("../../core/dom_adapter")); var _element = require("../../core/element"); var _errors = _interopRequireDefault(require("../../core/errors")); var _renderer = _interopRequireDefault(require("../../core/renderer")); var _common = require("../../core/utils/common"); var _deferred = require("../../core/utils/deferred"); var _extend = require("../../core/utils/extend"); var _iterator = require("../../core/utils/iterator"); var _type = require("../../core/utils/type"); var _m_drop_down_list = _interopRequireDefault(require("../ui/drop_down_editor/m_drop_down_list")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function(n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]) } } return n }, _extends.apply(null, arguments) } const DISABLED_STATE_SELECTOR = ".dx-state-disabled"; const SELECTBOX_CLASS = "dx-selectbox"; const SELECTBOX_POPUP_CLASS = "dx-selectbox-popup"; const SELECTBOX_CONTAINER_CLASS = "dx-selectbox-container"; const SELECTBOX_POPUP_WRAPPER_CLASS = "dx-selectbox-popup-wrapper"; class SelectBox extends _m_drop_down_list.default { _supportedKeys() { const that = this; const parent = super._supportedKeys(); const clearSelectBox = function(e) { const isEditable = this._isEditable(); if (!isEditable) { if (this.option("showClearButton")) { e.preventDefault(); this.clear() } } else if (this._valueSubstituted()) { this._preventFiltering = true } this._savedTextRemoveEvent = e; this._preventSubstitution = true }; const searchIfNeeded = function() { if (that.option("searchEnabled") && that._valueSubstituted()) { that._searchHandler() } }; return _extends({}, parent, { tab() { const { opened: opened } = this.option(); const popupHasFocusableElements = opened && !!this._popup.getFocusableElements().length; if (!popupHasFocusableElements) { this._resetCaretPosition(true) } parent.tab && parent.tab.apply(this, arguments); if (!popupHasFocusableElements) { this._cancelSearchIfNeed() } }, upArrow(e) { if (parent.upArrow.apply(this, arguments)) { if (!this.option("opened")) { this._setNextValue(e) } return true } return }, downArrow(e) { if (parent.downArrow.apply(this, arguments)) { if (!this.option("opened")) { this._setNextValue(e) } return true } return }, leftArrow() { var _parent$leftArrow; searchIfNeeded(); null === (_parent$leftArrow = parent.leftArrow) || void 0 === _parent$leftArrow || _parent$leftArrow.apply(this, arguments) }, rightArrow() { var _parent$rightArrow; searchIfNeeded(); null === (_parent$rightArrow = parent.rightArrow) || void 0 === _parent$rightArrow || _parent$rightArrow.apply(this, arguments) }, home() { var _parent$home; searchIfNeeded(); null === (_parent$home = parent.home) || void 0 === _parent$home || _parent$home.apply(this, arguments) }, end() { var _parent$end; searchIfNeeded(); null === (_parent$end = parent.end) || void 0 === _parent$end || _parent$end.apply(this, arguments) }, escape() { var _parent$escape; const result = null === (_parent$escape = parent.escape) || void 0 === _parent$escape ? void 0 : _parent$escape.apply(this, arguments); this._cancelEditing(); return result ?? true }, enter(e) { const isOpened = this.option("opened"); const inputText = this._input().val().trim(); const isCustomText = inputText && this._list && !this._list.option("focusedElement"); if (!inputText && (0, _type.isDefined)(this.option("value")) && this.option("allowClearing")) { this._saveValueChangeEvent(e); this.option({ selectedItem: null, value: null }); this.close() } else { var _parent$enter; if (this.option("acceptCustomValue")) { e.preventDefault(); if (isCustomText) { if (isOpened) { this._toggleOpenState() } this._valueChangeEventHandler(e) } return isOpened } if (null !== (_parent$enter = parent.enter) && void 0 !== _parent$enter && _parent$enter.apply(this, arguments)) { return isOpened } } }, space(e) { const isOpened = this.option("opened"); const isSearchEnabled = this.option("searchEnabled"); const acceptCustomValue = this.option("acceptCustomValue"); if (!isOpened || isSearchEnabled || acceptCustomValue) { return } e.preventDefault(); this._valueChangeEventHandler(e); return true }, backspace: clearSelectBox, del: clearSelectBox }) } _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { placeholder: _message.default.format("Select"), fieldTemplate: null, customItemCreateEvent: "change", valueChangeEvent: "change", acceptCustomValue: false, onCustomItemCreating(e) { if (!(0, _type.isDefined)(e.customItem)) { e.customItem = e.text } }, showSelectionControls: false, allowClearing: true, tooltipEnabled: false, openOnFieldClick: true, showDropDownButton: true, displayCustomValue: false, useHiddenSubmitElement: true }) } _init() { super._init(); this._initCustomItemCreatingAction() } _initMarkup() { this.$element().addClass("dx-selectbox"); this._renderTooltip(); super._initMarkup(); this._$container.addClass("dx-selectbox-container") } _createPopup() { var _this$_popup, _this$_popup2; super._createPopup(); null === (_this$_popup = this._popup) || void 0 === _this$_popup || _this$_popup.$element().addClass("dx-selectbox-popup"); null === (_this$_popup2 = this._popup) || void 0 === _this$_popup2 || _this$_popup2.$overlayContent().attr("tabindex", -1) } _popupWrapperClass() { return `${super._popupWrapperClass()} dx-selectbox-popup-wrapper` } _setDeprecatedOptions() { super._setDeprecatedOptions(); (0, _extend.extend)(this._deprecatedOptions, { valueChangeEvent: { since: "22.2", alias: "customItemCreateEvent" } }) } _cancelEditing() { if (!this.option("searchEnabled") && this._list) { this._focusListElement(null); this._updateField(this.option("selectedItem")) } } _renderOpenedState() { super._renderOpenedState(); if (this.option("opened")) { this._scrollToSelectedItem(); this._focusSelectedElement() } } _focusSelectedElement() { const searchValue = this._searchValue(); if (!searchValue) { this._focusListElement(null); return } const { items: items, selectedItem: selectedItem } = this.option(); const $listItems = this._list._itemElements(); const index = (null === items || void 0 === items ? void 0 : items.indexOf(selectedItem)) ?? -1; const focusedElement = -1 !== index && !this._isCustomItemSelected() ? $listItems.eq(index) : null; this._focusListElement(focusedElement) } _renderFocusedElement() { if (!this._list) { return } const searchValue = this._searchValue(); if (!searchValue || this.option("acceptCustomValue")) { this._focusListElement(null); return } const $listItems = this._list._itemElements(); const focusedElement = $listItems.not(".dx-state-disabled").eq(0); this._focusListElement(focusedElement) } _focusListElement(element) { this._preventInputValueRender = true; this._list.option("focusedElement", (0, _element.getPublicElement)(element)); delete this._preventInputValueRender } _scrollToSelectedItem() { var _this$_list; null === (_this$_list = this._list) || void 0 === _this$_list || _this$_list.scrollToItem(this._list.option("selectedItem")) } _listContentReadyHandler() { super._listContentReadyHandler(); const isPaginate = this._dataController.paginate(); if (isPaginate && this._needPopupRepaint()) { return } this._scrollToSelectedItem() } _renderValue() { this._renderInputValue(); this._setSubmitValue(); return (0, _deferred.Deferred)().resolve() } _renderInputValue() { return super._renderInputValue(...arguments).always((() => { this._renderInputValueAsync() })) } _renderInputValueAsync() { this._renderTooltip(); this._renderInputValueImpl().always((() => { this._refreshSelected() })) } _renderInputValueImpl() { this._renderField(); return (0, _deferred.Deferred)().resolve() } _setNextItem(step) { const item = this._calcNextItem(step); const value = this._valueGetter(item); this._setValue(value) } _setNextValue(e) { const dataSourceIsLoaded = this._dataController.isLoaded() ? (0, _deferred.Deferred)().resolve() : this._dataController.load(); dataSourceIsLoaded.done((() => { const selectedIndex = this._getSelectedIndex(); const hasPages = this._dataController.pageSize(); const isLastPage = this._dataController.isLastPage(); const isLastItem = selectedIndex === this._items().length - 1; this._saveValueChangeEvent(e); const step = "downArrow" === (0, _index.normalizeKeyName)(e) ? 1 : -1; if (hasPages && !isLastPage && isLastItem && step > 0) { if (!this._popup) { this._createPopup() } if (!this._dataController.isLoading()) { this._list._loadNextPage().done(this._setNextItem.bind(this, step)) } } else { this._setNextItem(step) } })) } _setSelectedItem(item) { const isUnknownItem = !this._isCustomValueAllowed() && void 0 === item; super._setSelectedItem(isUnknownItem ? null : item); if (!isUnknownItem && (!this._isEditable() || this._isCustomItemSelected())) { this._setListOption("selectedItem", this.option("selectedItem")) } } _isCustomValueAllowed() { return this.option("acceptCustomValue") || super._isCustomValueAllowed() } _displayValue(item) { item = !(0, _type.isDefined)(item) && this._isCustomValueAllowed() ? this.option("value") : item; return super._displayValue(item) } _listConfig() { const result = (0, _extend.extend)(super._listConfig(), { pageLoadMode: "scrollBottom", onSelectionChanged: this._getSelectionChangeHandler(), selectedItem: this.option("selectedItem"), onFocusedItemChanged: this._listFocusedItemChangeHandler.bind(this), _onItemsRendered: () => { this._popup.repaint(); if (this.option("opened")) { this._scrollToSelectedItem() } } }); if (this.option("showSelectionControls")) { (0, _extend.extend)(result, { showSelectionControls: true, selectByClick: true }) } return result } _listFocusedItemChangeHandler(e) { if (this._preventInputValueRender) { return } const list = e.component; const focusedElement = (0, _renderer.default)(list.option("focusedElement")); const focusedItem = list._getItemData(focusedElement); this._updateField(focusedItem) } _updateField(item) { const fieldTemplate = this._getTemplateByOption("fieldTemplate"); if (!(fieldTemplate && this.option("fieldTemplate"))) { const text = this._displayGetter(item); this.option("text", text); this._renderDisplayText(text); return } this._renderField() } _getSelectionChangeHandler() { return this.option("showSelectionControls") ? this._selectionChangeHandler.bind(this) : _common.noop } _selectionChangeHandler(e) { (0, _iterator.each)(e.addedItems || [], ((_, addedItem) => { this._setValue(this._valueGetter(addedItem)) })) } _getActualSearchValue() { return this._dataController.searchValue() } _isInlineAutocompleteEnabled() { const { searchEnabled: searchEnabled, acceptCustomValue: acceptCustomValue, searchMode: searchMode } = this.option(); return searchEnabled && !acceptCustomValue && "startswith" === searchMode } _getAriaAutocomplete() { const { disabled: disabled, readOnly: readOnly, searchEnabled: searchEnabled } = this.option(); const isInputEditable = !(readOnly || disabled); const hasAutocomplete = searchEnabled && isInputEditable; if (!hasAutocomplete) { return "none" } const isInlineAutocompleteEnabled = this._isInlineAutocompleteEnabled(); const autocompleteAria = isInlineAutocompleteEnabled ? "both" : "list"; return autocompleteAria } _toggleOpenState(isVisible) { if (this.option("disabled")) { return } isVisible = arguments.length ? isVisible : !this.option("opened"); if (!isVisible && !this._shouldClearFilter()) { this._restoreInputText(true) } if (this._wasSearch() && isVisible) { this._wasSearch(false); const showDataImmediately = this.option("showDataBeforeSearch") || this._isMinSearchLengthExceeded(); if (showDataImmediately && this._dataController.getDataSource()) { if (this._searchTimer) { return } const searchValue = this._getActualSearchValue(); searchValue && this._wasSearch(true); this._filterDataSource(searchValue || null) } else { this._setListOption("items", []) } } if (isVisible) { this._scrollToSelectedItem() } super._toggleOpenState(isVisible) } _renderTooltip() { const { tooltipEnabled: tooltipEnabled, displayValue: displayValue } = this.option(); if (tooltipEnabled) { this.$element().attr("title", displayValue) } } _renderDimensions() { super._renderDimensions(); this._updatePopupWidth(); this._updateListDimensions() } _isValueEqualInputText() { const initialSelectedItem = this.option("selectedItem"); if (null === initialSelectedItem) { return false } const value = this._displayGetter(initialSelectedItem); const displayValue = value ? String(value) : ""; const inputText = this._searchValue(); return displayValue === inputText } _popupHidingHandler() { if (this._isValueEqualInputText()) { this._cancelEditing() } super._popupHidingHandler() } _popupHiddenHandler() { super._popupHiddenHandler(); if (this._shouldCancelSearch()) { this._wasSearch(false); this._searchCanceled(); this._shouldCancelSearch(false) } } _restoreInputText(saveEditingValue) { var _this$_loadItemDeferr; if (this.option("readOnly")) { return } null === (_this$_loadItemDeferr = this._loadItemDeferred) || void 0 === _this$_loadItemDeferr || _this$_loadItemDeferr.always((() => { const { acceptCustomValue: acceptCustomValue, text: text, selectedItem: initialSelectedItem, customItemCreateEvent: customItemCreateEvent } = this.option(); if (acceptCustomValue) { if (!saveEditingValue && !this._isValueChanging) { let initialItem = null; if ((0, _type.isDefined)(initialSelectedItem)) { initialItem = initialSelectedItem } else if ("" !== customItemCreateEvent) { initialItem = this._createCustomItem(text) } this._updateField(initialItem); this._clearFilter() } return } if (this.option("searchEnabled")) { if (!this._searchValue() && this.option("allowClearing")) { this._clearTextValue(); return } } if (this._isValueEqualInputText()) { return } this._renderInputValue().always((selectedItem => { const newSelectedItem = (0, _common.ensureDefined)(selectedItem, initialSelectedItem); this._setSelectedItem(newSelectedItem); this._updateField(newSelectedItem); this._clearFilter() })) })) } _valueChangeEventIncludesBlur() { const valueChangeEvent = this.option(this._getValueChangeEventOptionName()); return valueChangeEvent.includes("blur") } _isPreventedFocusOutEvent(e) { return this._preventNestedFocusEvent(e) || this._valueChangeEventIncludesBlur() } _focusOutHandler(e) { if (!this._isPreventedFocusOutEvent(e)) { const isOverlayTarget = this._isOverlayNestedTarget(e.relatedTarget); if (!isOverlayTarget) { this._restoreInputText(); this._clearSearchTimer() } this._cancelSearchIfNeed(e) } e.target = this._input().get(0); super._focusOutHandler(e) } _cancelSearchIfNeed(e) { const { searchEnabled: searchEnabled } = this.option(); const isOverlayTarget = this._isOverlayNestedTarget(null === e || void 0 === e ? void 0 : e.relatedTarget); const shouldCancelSearch = this._wasSearch() && searchEnabled && !isOverlayTarget; if (shouldCancelSearch) { var _this$_popup3; const isPopupVisible = null === (_this$_popup3 = this._popup) || void 0 === _this$_popup3 ? void 0 : _this$_popup3._hideAnimationProcessing; this._clearSearchTimer(); if (isPopupVisible) { this._shouldCancelSearch(true) } else { this._wasSearch(false); this._searchCanceled() } } } _shouldCancelSearch(value) { if (!arguments.length) { return this._shouldCancelSearchValue } this._shouldCancelSearchValue = value } _isOverlayNestedTarget(target) { return !!(0, _renderer.default)(target).closest(".dx-selectbox-popup-wrapper").length } _clearTextValue() { const selectedItem = this.option("selectedItem"); const selectedItemText = this._displayGetter(selectedItem); const shouldRestoreValue = selectedItem && "" !== selectedItemText; if (shouldRestoreValue) { if (this._savedTextRemoveEvent) { this._saveValueChangeEvent(this._savedTextRemoveEvent) } this.option("value", null) } delete this._savedTextRemoveEvent } _shouldOpenPopup() { return this._needPassDataSourceToList() && this._wasSearch() } _isFocused() { const activeElement = _dom_adapter.default.getActiveElement(this.element()); return super._isFocused() && (0, _renderer.default)(activeElement).closest(this._input()).length > 0 } _getValueChangeEventOptionName() { return "customItemCreateEvent" } _renderValueChangeEvent() { if (this._isEditable()) { super._renderValueChangeEvent() } } _fieldRenderData() { const { focusedElement: focusedElement } = this.option(); const $listFocused = this._list && this.option("opened") && (0, _renderer.default)(focusedElement); if (null !== $listFocused && void 0 !== $listFocused && $listFocused.length) { return this._list._getItemData($listFocused) } return this.option("selectedItem") } _isSelectedValue(value, cache) { return this._isValueEquals(value, this.option("value")) } _shouldCloseOnItemClick() { const { selectionMode: selectionMode } = this.option(); return !(this.option("showSelectionControls") && "single" !== selectionMode) } _listItemClickHandler(e) { const previousValue = this._getCurrentValue(); this._focusListElement((0, _renderer.default)(e.itemElement)); this._saveValueChangeEvent(e.event); this._completeSelection(this._valueGetter(e.itemData)); if (this._shouldCloseOnItemClick()) { this.option("opened", false) } if (this.option("searchEnabled") && previousValue === this._valueGetter(e.itemData)) { this._updateField(e.itemData) } if (this._shouldClearFilter()) { this._cancelSearchIfNeed() } } _shouldClearFilter() { return this._wasSearch() } _completeSelection(value) { this._setValue(value) } _loadItem(value, cache) { const that = this; const deferred = (0, _deferred.Deferred)(); super._loadItem(value, cache).done((item => { deferred.resolve(item) })).fail((args => { if (null !== args && void 0 !== args && args.shouldSkipCallback) { return } const selectedItem = that.option("selectedItem"); if (that.option("acceptCustomValue") && value === that._valueGetter(selectedItem)) { deferred.resolve(selectedItem) } else { deferred.reject() } })); return deferred.promise() } _loadInputValue(value, callback) { this._loadItemDeferred = this._loadItem(value).always(callback); return this._loadItemDeferred } _isCustomItemSelected() { const selectedItem = this.option("selectedItem"); const searchValue = this._searchValue(); const selectedItemText = this._displayGetter(selectedItem); return !selectedItemText || searchValue !== selectedItemText.toString() } _valueChangeEventHandler(e) { if (this.option("acceptCustomValue") && this._isCustomItemSelected() && !this._isValueChanging) { this._isValueChanging = true; this._customItemAddedHandler(e) } } _initCustomItemCreatingAction() { this._customItemCreatingAction = this._createActionByOption("onCustomItemCreating") } _createCustomItem(text) { const params = { text: text }; const actionResult = this._customItemCreatingAction(params); const item = (0, _common.ensureDefined)(actionResult, params.customItem); if ((0, _type.isDefined)(actionResult)) { _errors.default.log("W0015", "onCustomItemCreating", "customItem") } return item } _customItemAddedHandler(e) { const searchValue = this._searchValue(); const item = this._createCustomItem(searchValue); this._saveValueChangeEvent(e); if (void 0 === item) { this._renderValue(); throw _errors.default.Error("E0121") } if ((0, _type.isPromise)(item)) { (0, _deferred.fromPromise)(item).done(this._setCustomItem.bind(this)).fail(this._setCustomItem.bind(this, null)) } else { this._setCustomItem(item) } } _setCustomItem(item) { if (this._disposed) { return } item = item || null; this.option("selectedItem", item); this._cancelSearchIfNeed(); this._setValue(this._valueGetter(item)); this._renderDisplayText(this._displayGetter(item)); this._isValueChanging = false } _clearValueHandler(e) { this._preventFiltering = true; super._clearValueHandler(e); this._searchCanceled(); return false } _wasSearch(value) { if (!arguments.length) { return !!this._wasSearchValue } this._wasSearchValue = value; return } _searchHandler(e) { if (this._preventFiltering) { delete this._preventFiltering; return } if (this._needPassDataSourceToList()) { this._wasSearch(true) } super._searchHandler(arguments) } _dataSourceFiltered(searchValue) { super._dataSourceFiltered(); if (null !== searchValue) { this._renderInputSubstitution(); this._renderFocusedElement() } } _valueSubstituted() { const input = this._input().get(0); const currentSearchLength = this._searchValue().length; const isAllSelected = 0 === input.selectionStart && input.selectionEnd === currentSearchLength; const inputHasSelection = input.selectionStart !== input.selectionEnd; const isLastSymbolSelected = currentSearchLength === input.selectionEnd; return this._wasSearch() && inputHasSelection && !isAllSelected && isLastSymbolSelected && this._shouldSubstitutionBeRendered() } _shouldSubstitutionBeRendered() { return !this._preventSubstitution && this._isInlineAutocompleteEnabled() } _renderInputSubstitution() { if (!this._shouldSubstitutionBeRendered()) { delete this._preventSubstitution; return } const item = this._list && this._getPlainItems(this._list.option("items"))[0]; if (!item) { return } const $input = this._input(); const valueLength = $input.val().length; if (0 === valueLength) { return } const inputElement = $input.get(0); const displayValue = this._displayGetter(item).toString(); inputElement.value = displayValue; this._caret({ start: valueLength, end: displayValue.length }) } _dispose() { this._renderInputValueAsync = _common.noop; delete this._loadItemDeferred; super._dispose() } _optionChanged(args) { switch (args.name) { case "customItemCreateEvent": this._refreshValueChangeEvent(); this._refreshFocusEvent(); this._refreshEvents(); break; case "onCustomItemCreating": this._initCustomItemCreatingAction(); break; case "tooltipEnabled": this._renderTooltip(); break; case "readOnly": case "disabled": case "searchMode": super._optionChanged(args); this._setDefaultAria(); break; case "displayCustomValue": case "acceptCustomValue": case "showSelectionControls": this._invalidate(); break; case "allowClearing": break; default: super._optionChanged(args) } } }(0, _component_registrator.default)("dxSelectBox", SelectBox); var _default = exports.default = SelectBox;