UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

804 lines (802 loc) • 32.4 kB
/** * DevExtreme (cjs/ui/drop_down_editor/ui.drop_down_editor.js) * Version: 23.2.6 * Build date: Wed May 01 2024 * * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; exports.default = void 0; var _renderer = _interopRequireDefault(require("../../core/renderer")); var _events_engine = _interopRequireDefault(require("../../events/core/events_engine")); var _guid = _interopRequireDefault(require("../../core/guid")); var _component_registrator = _interopRequireDefault(require("../../core/component_registrator")); var _common = require("../../core/utils/common"); var _selectors = require("../widget/selectors"); var _iterator = require("../../core/utils/iterator"); var _type = require("../../core/utils/type"); var _extend = require("../../core/utils/extend"); var _element = require("../../core/element"); var _ui = _interopRequireDefault(require("../widget/ui.errors")); var _position = _interopRequireDefault(require("../../animation/position")); var _position2 = require("../../core/utils/position"); var _ui2 = _interopRequireDefault(require("./ui.drop_down_button")); var _ui3 = _interopRequireDefault(require("../widget/ui.widget")); var _message = _interopRequireDefault(require("../../localization/message")); var _index = require("../../events/utils/index"); var _text_box = _interopRequireDefault(require("../text_box")); var _click = require("../../events/click"); var _devices = _interopRequireDefault(require("../../core/devices")); var _function_template = require("../../core/templates/function_template"); var _ui4 = _interopRequireDefault(require("../popup/ui.popup")); var _window = require("../../core/utils/window"); var _utils = require("./utils"); var _translator = require("../../animation/translator"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj } } const DROP_DOWN_EDITOR_CLASS = "dx-dropdowneditor"; const DROP_DOWN_EDITOR_INPUT_WRAPPER = "dx-dropdowneditor-input-wrapper"; const DROP_DOWN_EDITOR_BUTTON_ICON = "dx-dropdowneditor-icon"; const DROP_DOWN_EDITOR_OVERLAY = "dx-dropdowneditor-overlay"; const DROP_DOWN_EDITOR_OVERLAY_FLIPPED = "dx-dropdowneditor-overlay-flipped"; const DROP_DOWN_EDITOR_ACTIVE = "dx-dropdowneditor-active"; const DROP_DOWN_EDITOR_FIELD_CLICKABLE = "dx-dropdowneditor-field-clickable"; const DROP_DOWN_EDITOR_FIELD_TEMPLATE_WRAPPER = "dx-dropdowneditor-field-template-wrapper"; const isIOs = "ios" === _devices.default.current().platform; const DropDownEditor = _text_box.default.inherit({ _supportedKeys: function() { return (0, _extend.extend)({}, this.callBase(), { tab: function(e) { if (!this.option("opened")) { return } if (!this._popup.getFocusableElements().length) { this.close(); return } const $focusableElement = e.shiftKey ? this._getLastPopupElement() : this._getFirstPopupElement(); if ($focusableElement) { _events_engine.default.trigger($focusableElement, "focus"); $focusableElement.select() } e.preventDefault() }, escape: function(e) { if (this.option("opened")) { e.preventDefault() } this.close(); return true }, upArrow: function(e) { if (!(0, _index.isCommandKeyPressed)(e)) { e.preventDefault(); e.stopPropagation(); if (e.altKey) { this.close(); return false } } return true }, downArrow: function(e) { if (!(0, _index.isCommandKeyPressed)(e)) { e.preventDefault(); e.stopPropagation(); if (e.altKey) { this._validatedOpening(); return false } } return true }, enter: function(e) { if (this.option("opened")) { e.preventDefault(); this._valueChangeEventHandler(e) } return true } }) }, _getDefaultButtons: function() { return this.callBase().concat([{ name: "dropDown", Ctor: _ui2.default }]) }, _getDefaultOptions: function() { return (0, _extend.extend)(this.callBase(), { value: null, onOpened: null, onClosed: null, opened: false, acceptCustomValue: true, applyValueMode: "instantly", deferRendering: true, activeStateEnabled: true, dropDownButtonTemplate: "dropDownButton", fieldTemplate: null, openOnFieldClick: false, showDropDownButton: true, buttons: void 0, dropDownOptions: { showTitle: false }, popupPosition: this._getDefaultPopupPosition(), onPopupInitialized: null, applyButtonText: _message.default.format("OK"), cancelButtonText: _message.default.format("Cancel"), buttonsLocation: "default", useHiddenSubmitElement: false, validationMessagePosition: "auto" }) }, _useTemplates: function() { return true }, _getDefaultPopupPosition: function(isRtlEnabled) { const position = (0, _position2.getDefaultAlignment)(isRtlEnabled); return { offset: { h: 0, v: -1 }, my: position + " top", at: position + " bottom", collision: "flip flip" } }, _defaultOptionsRules: function() { return this.callBase().concat([{ device: function(device) { const isGeneric = "generic" === device.platform; return isGeneric }, options: { popupPosition: { offset: { v: 0 } } } }]) }, _inputWrapper: function() { return this.$element().find(".dx-dropdowneditor-input-wrapper").first() }, _init: function() { this.callBase(); this._initVisibilityActions(); this._initPopupInitializedAction(); this._updatePopupPosition(this.option("rtlEnabled")); this._options.cache("dropDownOptions", this.option("dropDownOptions")) }, _updatePopupPosition: function(isRtlEnabled) { const { my: my, at: at } = this._getDefaultPopupPosition(isRtlEnabled); const currentPosition = this.option("popupPosition"); this.option("popupPosition", (0, _extend.extend)({}, currentPosition, { my: my, at: at })) }, _initVisibilityActions: function() { this._openAction = this._createActionByOption("onOpened", { excludeValidators: ["disabled", "readOnly"] }); this._closeAction = this._createActionByOption("onClosed", { excludeValidators: ["disabled", "readOnly"] }) }, _initPopupInitializedAction: function() { this._popupInitializedAction = this._createActionByOption("onPopupInitialized", { excludeValidators: ["disabled", "readOnly"] }) }, _initMarkup: function() { this._renderSubmitElement(); this.callBase(); this.$element().addClass("dx-dropdowneditor"); this.setAria("role", "combobox") }, _render: function() { this.callBase(); this._renderOpenHandler(); this._attachFocusOutHandler(); this._renderOpenedState() }, _renderContentImpl: function() { if (!this.option("deferRendering")) { this._createPopup() } }, _renderInput: function() { this.callBase(); this._wrapInput(); this._setDefaultAria() }, _wrapInput: function() { this._$container = this.$element().wrapInner((0, _renderer.default)("<div>").addClass(DROP_DOWN_EDITOR_INPUT_WRAPPER)).children().eq(0) }, _setDefaultAria: function() { this.setAria({ haspopup: "true", autocomplete: "list" }) }, _readOnlyPropValue: function() { return !this._isEditable() || this.callBase() }, _cleanFocusState: function() { this.callBase(); if (this.option("fieldTemplate")) { this._detachFocusEvents() } }, _getFieldTemplate: function() { return this.option("fieldTemplate") && this._getTemplateByOption("fieldTemplate") }, _renderMask: function() { if (this.option("fieldTemplate")) { return } this.callBase() }, _renderField: function() { const fieldTemplate = this._getFieldTemplate(); fieldTemplate && this._renderTemplatedField(fieldTemplate, this._fieldRenderData()) }, _renderPlaceholder: function() { const hasFieldTemplate = !!this._getFieldTemplate(); if (!hasFieldTemplate) { this.callBase() } }, _renderValue: function() { if (this.option("useHiddenSubmitElement")) { this._setSubmitValue() } const promise = this.callBase(); promise.always(this._renderField.bind(this)) }, _renderTemplatedField: function(fieldTemplate, data) { const isFocused = (0, _selectors.focused)(this._input()); const $container = this._$container; this._detachKeyboardEvents(); this._refreshButtonsContainer(); this._detachWrapperContent(); this._detachFocusEvents(); $container.empty(); const $templateWrapper = (0, _renderer.default)("<div>").addClass(DROP_DOWN_EDITOR_FIELD_TEMPLATE_WRAPPER).appendTo($container); fieldTemplate.render({ model: data, container: (0, _element.getPublicElement)($templateWrapper), onRendered: () => { const isRenderedInRoot = !!this.$element().find($templateWrapper).length; if (!isRenderedInRoot) { return } const $input = this._input(); if (!$input.length) { throw _ui.default.Error("E1010") } this._integrateInput(); isFocused && _events_engine.default.trigger($input, "focus") } }); this._attachWrapperContent($container) }, _detachWrapperContent() { var _this$_$submitElement, _this$_$beforeButtons, _this$_$afterButtonsC; const useHiddenSubmitElement = this.option("useHiddenSubmitElement"); useHiddenSubmitElement && (null === (_this$_$submitElement = this._$submitElement) || void 0 === _this$_$submitElement ? void 0 : _this$_$submitElement.detach()); const beforeButtonsContainerParent = null === (_this$_$beforeButtons = this._$beforeButtonsContainer) || void 0 === _this$_$beforeButtons ? void 0 : _this$_$beforeButtons[0].parentNode; const afterButtonsContainerParent = null === (_this$_$afterButtonsC = this._$afterButtonsContainer) || void 0 === _this$_$afterButtonsC ? void 0 : _this$_$afterButtonsC[0].parentNode; null === beforeButtonsContainerParent || void 0 === beforeButtonsContainerParent ? void 0 : beforeButtonsContainerParent.removeChild(this._$beforeButtonsContainer[0]); null === afterButtonsContainerParent || void 0 === afterButtonsContainerParent ? void 0 : afterButtonsContainerParent.removeChild(this._$afterButtonsContainer[0]) }, _attachWrapperContent($container) { var _this$_$submitElement2; const useHiddenSubmitElement = this.option("useHiddenSubmitElement"); $container.prepend(this._$beforeButtonsContainer); useHiddenSubmitElement && (null === (_this$_$submitElement2 = this._$submitElement) || void 0 === _this$_$submitElement2 ? void 0 : _this$_$submitElement2.appendTo($container)); $container.append(this._$afterButtonsContainer) }, _refreshButtonsContainer() { this._$buttonsContainer = this.$element().children().eq(0) }, _integrateInput: function() { this._renderFocusState(); this._refreshValueChangeEvent(); this._refreshEvents(); this._refreshEmptinessEvent() }, _refreshEmptinessEvent: function() { _events_engine.default.off(this._input(), "input blur", this._toggleEmptinessEventHandler); this._renderEmptinessEvent() }, _fieldRenderData: function() { return this.option("value") }, _initTemplates: function() { this._templateManager.addDefaultTemplates({ dropDownButton: new _function_template.FunctionTemplate((function(options) { const $icon = (0, _renderer.default)("<div>").addClass("dx-dropdowneditor-icon"); (0, _renderer.default)(options.container).append($icon) })) }); this.callBase() }, _renderOpenHandler: function() { const $inputWrapper = this._inputWrapper(); const eventName = (0, _index.addNamespace)(_click.name, this.NAME); const openOnFieldClick = this.option("openOnFieldClick"); _events_engine.default.off($inputWrapper, eventName); _events_engine.default.on($inputWrapper, eventName, this._getInputClickHandler(openOnFieldClick)); this.$element().toggleClass(DROP_DOWN_EDITOR_FIELD_CLICKABLE, openOnFieldClick); if (openOnFieldClick) { this._openOnFieldClickAction = this._createAction(this._openHandler.bind(this)) } }, _attachFocusOutHandler: function() { if (isIOs) { this._detachFocusOutEvents(); _events_engine.default.on(this._inputWrapper(), (0, _index.addNamespace)("focusout", this.NAME), event => { const newTarget = event.relatedTarget; if (newTarget && this.option("opened")) { const isNewTargetOutside = this._isTargetOutOfComponent(newTarget); if (isNewTargetOutside) { this.close() } } }) } }, _isTargetOutOfComponent: function(newTarget) { const popupWrapper = this.content ? (0, _renderer.default)(this.content()).closest(".".concat(DROP_DOWN_EDITOR_OVERLAY)) : this._$popup; const isTargetOutsidePopup = 0 === (0, _renderer.default)(newTarget).closest(".".concat(DROP_DOWN_EDITOR_OVERLAY), popupWrapper).length; return isTargetOutsidePopup }, _detachFocusOutEvents: function() { isIOs && _events_engine.default.off(this._inputWrapper(), (0, _index.addNamespace)("focusout", this.NAME)) }, _getInputClickHandler: function(openOnFieldClick) { return openOnFieldClick ? e => { this._executeOpenAction(e) } : e => { this._focusInput() } }, _openHandler: function() { this._toggleOpenState() }, _executeOpenAction: function(e) { this._openOnFieldClickAction({ event: e }) }, _keyboardEventBindingTarget: function() { return this._input() }, _focusInput: function() { if (this.option("disabled")) { return false } if (this.option("focusStateEnabled") && !(0, _selectors.focused)(this._input())) { this._resetCaretPosition(); _events_engine.default.trigger(this._input(), "focus") } return true }, _resetCaretPosition: function() { let ignoreEditable = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : false; const inputElement = this._input().get(0); if (inputElement) { const { value: value } = inputElement; const caretPosition = (0, _type.isDefined)(value) && (ignoreEditable || this._isEditable()) ? value.length : 0; this._caret({ start: caretPosition, end: caretPosition }, true) } }, _isEditable: function() { return this.option("acceptCustomValue") }, _toggleOpenState: function(isVisible) { if (!this._focusInput()) { return } if (!this.option("readOnly")) { isVisible = arguments.length ? isVisible : !this.option("opened"); this.option("opened", isVisible) } }, _getControlsAria() { return this._popup && this._popupContentId }, _renderOpenedState: function() { const opened = this.option("opened"); if (opened) { this._createPopup() } this.$element().toggleClass(DROP_DOWN_EDITOR_ACTIVE, opened); this._setPopupOption("visible", opened); const arias = { expanded: opened, controls: this._getControlsAria() }; this.setAria(arias); this.setAria("owns", opened ? this._popupContentId : void 0, this.$element()) }, _createPopup: function() { if (this._$popup) { return } this._$popup = (0, _renderer.default)("<div>").addClass(DROP_DOWN_EDITOR_OVERLAY).appendTo(this.$element()); this._renderPopup(); this._renderPopupContent() }, _renderPopupContent: _common.noop, _renderPopup: function() { const popupConfig = (0, _extend.extend)(this._popupConfig(), this._options.cache("dropDownOptions")); delete popupConfig.closeOnOutsideClick; if (popupConfig.elementAttr && !Object.keys(popupConfig.elementAttr).length) { delete popupConfig.elementAttr } this._popup = this._createComponent(this._$popup, _ui4.default, popupConfig); this._popup.on({ showing: this._popupShowingHandler.bind(this), shown: this._popupShownHandler.bind(this), hiding: this._popupHidingHandler.bind(this), hidden: this._popupHiddenHandler.bind(this), contentReady: this._contentReadyHandler.bind(this) }); this._attachPopupKeyHandler(); this._contentReadyHandler(); this._setPopupContentId(this._popup.$content()); this._bindInnerWidgetOptions(this._popup, "dropDownOptions") }, _attachPopupKeyHandler() { _events_engine.default.on(this._popup.$overlayContent(), (0, _index.addNamespace)("keydown", this.NAME), e => this._popupKeyHandler(e)) }, _popupKeyHandler(e) { switch ((0, _index.normalizeKeyName)(e)) { case "tab": this._popupTabHandler(e); break; case "escape": this._popupEscHandler(e) } }, _popupTabHandler(e) { const $target = (0, _renderer.default)(e.target); const moveBackward = e.shiftKey && $target.is(this._getFirstPopupElement()); const moveForward = !e.shiftKey && $target.is(this._getLastPopupElement()); if (moveForward || moveBackward) { _events_engine.default.trigger(this.field(), "focus"); e.preventDefault() } }, _popupEscHandler() { _events_engine.default.trigger(this._input(), "focus"); this.close() }, _setPopupContentId($popupContent) { this._popupContentId = "dx-" + new _guid.default; this.setAria("id", this._popupContentId, $popupContent) }, _contentReadyHandler: _common.noop, _popupConfig: function() { return { onInitialized: this._getPopupInitializedHandler(), position: (0, _extend.extend)(this.option("popupPosition"), { of: this.$element() }), showTitle: this.option("dropDownOptions.showTitle"), _ignoreFunctionValueDeprecation: true, width: () => (0, _utils.getElementWidth)(this.$element()), height: "auto", shading: false, hideOnParentScroll: true, hideOnOutsideClick: e => this._closeOutsideDropDownHandler(e), animation: { show: { type: "fade", duration: 0, from: 0, to: 1 }, hide: { type: "fade", duration: 400, from: 1, to: 0 } }, deferRendering: false, focusStateEnabled: false, showCloseButton: false, dragEnabled: false, toolbarItems: this._getPopupToolbarItems(), onPositioned: this._popupPositionedHandler.bind(this), fullScreen: false, contentTemplate: null, _hideOnParentScrollTarget: this.$element(), _wrapperClassExternal: DROP_DOWN_EDITOR_OVERLAY, _ignorePreventScrollEventsDeprecation: true } }, _popupInitializedHandler: _common.noop, _getPopupInitializedHandler: function() { const onPopupInitialized = this.option("onPopupInitialized"); return e => { this._popupInitializedHandler(e); if (onPopupInitialized) { this._popupInitializedAction({ popup: e.component }) } } }, _dimensionChanged: function() { if ((0, _window.hasWindow)() && !this.$element().is(":visible")) { this.close(); return } this._updatePopupWidth() }, _updatePopupWidth: function() { const popupWidth = (0, _utils.getSizeValue)(this.option("dropDownOptions.width")); if (void 0 === popupWidth) { this._setPopupOption("width", () => (0, _utils.getElementWidth)(this.$element())) } }, _popupPositionedHandler: function(e) { var _e$position, _e$position$v; const { labelMode: labelMode, stylingMode: stylingMode } = this.option(); if (!this._popup) { return } const $popupOverlayContent = this._popup.$overlayContent(); const isOverlayFlipped = null === (_e$position = e.position) || void 0 === _e$position ? void 0 : null === (_e$position$v = _e$position.v) || void 0 === _e$position$v ? void 0 : _e$position$v.flip; const shouldIndentForLabel = "hidden" !== labelMode && "outside" !== labelMode && "outlined" === stylingMode; if (e.position) { $popupOverlayContent.toggleClass(DROP_DOWN_EDITOR_OVERLAY_FLIPPED, isOverlayFlipped) } if (isOverlayFlipped && shouldIndentForLabel && this._label.isVisible()) { const $label = this._label.$element(); (0, _translator.move)($popupOverlayContent, { top: (0, _translator.locate)($popupOverlayContent).top - parseInt($label.css("fontSize")) }) } }, _popupShowingHandler: _common.noop, _popupHidingHandler: function() { this.option("opened", false) }, _popupShownHandler: function() { var _this$_validationMess; this._openAction(); null === (_this$_validationMess = this._validationMessage) || void 0 === _this$_validationMess ? void 0 : _this$_validationMess.option("positionSide", this._getValidationMessagePositionSide()) }, _popupHiddenHandler: function() { var _this$_validationMess2; this._closeAction(); null === (_this$_validationMess2 = this._validationMessage) || void 0 === _this$_validationMess2 ? void 0 : _this$_validationMess2.option("positionSide", this._getValidationMessagePositionSide()) }, _getValidationMessagePositionSide: function() { const validationMessagePosition = this.option("validationMessagePosition"); if ("auto" !== validationMessagePosition) { return validationMessagePosition } let positionSide = "bottom"; if (this._popup && this._popup.option("visible")) { const { top: myTop } = _position.default.setup(this.$element()); const { top: popupTop } = _position.default.setup(this._popup.$content()); positionSide = myTop + this.option("popupPosition").offset.v > popupTop ? "bottom" : "top" } return positionSide }, _closeOutsideDropDownHandler: function(_ref) { let { target: target } = _ref; const $target = (0, _renderer.default)(target); const dropDownButton = this.getButton("dropDown"); const $dropDownButton = dropDownButton && dropDownButton.$element(); const isInputClicked = !!$target.closest(this.$element()).length; const isDropDownButtonClicked = !!$target.closest($dropDownButton).length; const isOutsideClick = !isInputClicked && !isDropDownButtonClicked; return isOutsideClick }, _clean: function() { delete this._openOnFieldClickAction; if (this._$popup) { this._$popup.remove(); delete this._$popup; delete this._popup } this.callBase() }, _setPopupOption: function(optionName, value) { this._setWidgetOption("_popup", arguments) }, _validatedOpening: function() { if (!this.option("readOnly")) { this._toggleOpenState(true) } }, _getPopupToolbarItems: function() { return "useButtons" === this.option("applyValueMode") ? this._popupToolbarItemsConfig() : [] }, _getFirstPopupElement: function() { return (0, _renderer.default)(this._popup.getFocusableElements()).first() }, _getLastPopupElement: function() { return (0, _renderer.default)(this._popup.getFocusableElements()).last() }, _popupToolbarItemsConfig: function() { const buttonsConfig = [{ shortcut: "done", options: { onClick: this._applyButtonHandler.bind(this), text: this.option("applyButtonText") } }, { shortcut: "cancel", options: { onClick: this._cancelButtonHandler.bind(this), text: this.option("cancelButtonText") } }]; return this._applyButtonsLocation(buttonsConfig) }, _applyButtonsLocation: function(buttonsConfig) { const buttonsLocation = this.option("buttonsLocation"); const resultConfig = buttonsConfig; if ("default" !== buttonsLocation) { const position = (0, _common.splitPair)(buttonsLocation); (0, _iterator.each)(resultConfig, (function(_, element) { (0, _extend.extend)(element, { toolbar: position[0], location: position[1] }) })) } return resultConfig }, _applyButtonHandler: function() { this.close(); this.option("focusStateEnabled") && this.focus() }, _cancelButtonHandler: function() { this.close(); this.option("focusStateEnabled") && this.focus() }, _popupOptionChanged: function(args) { const options = _ui3.default.getOptionsFromContainer(args); this._setPopupOption(options); const optionsKeys = Object.keys(options); if (-1 !== optionsKeys.indexOf("width") || -1 !== optionsKeys.indexOf("height")) { this._dimensionChanged() } }, _renderSubmitElement: function() { if (this.option("useHiddenSubmitElement")) { this._$submitElement = (0, _renderer.default)("<input>").attr("type", "hidden").appendTo(this.$element()) } }, _setSubmitValue: function() { this._getSubmitElement().val(this.option("value")) }, _getSubmitElement: function() { if (this.option("useHiddenSubmitElement")) { return this._$submitElement } else { return this.callBase() } }, _dispose: function() { this._detachFocusOutEvents(); this.callBase() }, _optionChanged: function(args) { var _this$_popup; switch (args.name) { case "width": case "height": this.callBase(args); null === (_this$_popup = this._popup) || void 0 === _this$_popup ? void 0 : _this$_popup.repaint(); break; case "opened": this._renderOpenedState(); break; case "onOpened": case "onClosed": this._initVisibilityActions(); break; case "onPopupInitialized": this._initPopupInitializedAction(); break; case "fieldTemplate": if ((0, _type.isDefined)(args.value)) { this._renderField() } else { this._invalidate() } break; case "acceptCustomValue": case "openOnFieldClick": this._invalidate(); break; case "dropDownButtonTemplate": case "showDropDownButton": this._updateButtons(["dropDown"]); break; case "dropDownOptions": this._popupOptionChanged(args); this._options.cache("dropDownOptions", this.option("dropDownOptions")); break; case "popupPosition": break; case "deferRendering": if ((0, _window.hasWindow)()) { this._createPopup() } break; case "applyValueMode": case "applyButtonText": case "cancelButtonText": case "buttonsLocation": this._setPopupOption("toolbarItems", this._getPopupToolbarItems()); break; case "useHiddenSubmitElement": if (this._$submitElement) { this._$submitElement.remove(); this._$submitElement = void 0 } this._renderSubmitElement(); break; case "rtlEnabled": this._updatePopupPosition(args.value); this.callBase(args); break; default: this.callBase(args) } }, open: function() { this.option("opened", true) }, close: function() { this.option("opened", false) }, field: function() { return (0, _element.getPublicElement)(this._input()) }, content: function() { return this._popup ? this._popup.content() : null } }); (0, _component_registrator.default)("dxDropDownEditor", DropDownEditor); var _default = DropDownEditor; exports.default = _default; module.exports = exports.default; module.exports.default = exports.default;