UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

392 lines (391 loc) • 15 kB
/** * DevExtreme (esm/__internal/ui/editor/editor.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/ */ import _extends from "@babel/runtime/helpers/esm/extends"; import EventsEngine from "../../../common/core/events/core/events_engine"; import { addNamespace, normalizeKeyName } from "../../../common/core/events/utils/index"; import { data } from "../../../core/element_data"; import Guid from "../../../core/guid"; import $ from "../../../core/renderer"; import Callbacks from "../../../core/utils/callbacks"; import { extend } from "../../../core/utils/extend"; import { hasWindow } from "../../../core/utils/window"; import ValidationEngine from "../../../ui/validation_engine"; import ValidationMessage from "../../../ui/validation_message"; import Widget from "../../core/widget/widget"; import domUtils from "../../core/utils/m_dom"; const INVALID_MESSAGE_AUTO = "dx-invalid-message-auto"; const READONLY_STATE_CLASS = "dx-state-readonly"; const INVALID_CLASS = "dx-invalid"; const DX_INVALID_BADGE_CLASS = "dx-show-invalid-badge"; const VALIDATION_TARGET = "dx-validation-target"; const VALIDATION_STATUS_VALID = "valid"; const VALIDATION_STATUS_INVALID = "invalid"; const READONLY_NAMESPACE = "editorReadOnly"; const ALLOWED_STYLING_MODES = ["outlined", "filled", "underlined"]; const VALIDATION_MESSAGE_KEYS_MAP = { validationMessageMode: "mode", validationMessagePosition: "positionSide", validationMessageOffset: "offset", validationBoundary: "boundary" }; class Editor extends Widget { ctor(element, options) { this.showValidationMessageTimeout = void 0; this.validationRequest = Callbacks(); super.ctor(element, options) } _createElement(element) { super._createElement(element); const $element = this.$element(); if ($element) { data($element[0], VALIDATION_TARGET, this) } } _initOptions(options) { super._initOptions(options); this.option(ValidationEngine.initValidationOptions(options)) } _init() { this._initialValue = this.option("value"); super._init(); const { validationTooltipOptions: validationTooltipOptions } = this.option(); this._options.cache("validationTooltipOptions", validationTooltipOptions); const $element = this.$element(); $element.addClass(DX_INVALID_BADGE_CLASS) } _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { value: null, name: "", onValueChanged: null, readOnly: false, isValid: true, validationError: null, validationErrors: null, validationStatus: "valid", validationMessageMode: "auto", validationMessagePosition: "bottom", validationBoundary: void 0, validationMessageOffset: { h: 0, v: 0 }, validationTooltipOptions: {}, _showValidationMessage: true, isDirty: false }) } _attachKeyboardEvents() { if (!this.option("readOnly")) { super._attachKeyboardEvents() } } _setOptionsByReference() { super._setOptionsByReference(); extend(this._optionsByReference, { validationError: true }) } _createValueChangeAction() { this._valueChangeAction = this._createActionByOption("onValueChanged", { excludeValidators: ["disabled", "readOnly"] }) } _suppressValueChangeAction() { this._valueChangeActionSuppressed = true } _resumeValueChangeAction() { this._valueChangeActionSuppressed = false } _initMarkup() { this._toggleReadOnlyState(); const { name: name, _onMarkupRendered: markupRendered } = this.option(); this._setSubmitElementName(name); super._initMarkup(); this._renderValidationState(); null === markupRendered || void 0 === markupRendered || markupRendered() } _raiseValueChangeAction(value, previousValue) { if (!this._valueChangeAction) { this._createValueChangeAction() } this._valueChangeAction(this._valueChangeArgs(value, previousValue)) } _valueChangeArgs(value, previousValue) { return { value: value, previousValue: previousValue, event: this._valueChangeEventInstance } } _saveValueChangeEvent(e) { this._valueChangeEventInstance = e } _focusInHandler(e) { const { validationMessageMode: validationMessageMode } = this.option(); const isValidationMessageShownOnFocus = "auto" === validationMessageMode; if (this._canValueBeChangedByClick() && isValidationMessageShownOnFocus) { var _this$_validationMess; const $validationMessageWrapper = null === (_this$_validationMess = this._validationMessage) || void 0 === _this$_validationMess ? void 0 : _this$_validationMess.$wrapper(); null === $validationMessageWrapper || void 0 === $validationMessageWrapper || $validationMessageWrapper.removeClass(INVALID_MESSAGE_AUTO); clearTimeout(this.showValidationMessageTimeout); this.showValidationMessageTimeout = setTimeout((() => null === $validationMessageWrapper || void 0 === $validationMessageWrapper ? void 0 : $validationMessageWrapper.addClass(INVALID_MESSAGE_AUTO)), 150) } super._focusInHandler(e) } _canValueBeChangedByClick() { return false } _getStylingModePrefix() { return "dx-editor-" } _renderStylingMode() { const { stylingMode: stylingMode } = this.option(); const prefix = this._getStylingModePrefix(); const allowedStylingClasses = ALLOWED_STYLING_MODES.map((mode => prefix + mode)); allowedStylingClasses.forEach((className => this.$element().removeClass(className))); let stylingModeClass = prefix + String(stylingMode); if (!allowedStylingClasses.includes(stylingModeClass)) { const optionName = "stylingMode"; const defaultOptionValue = this._getDefaultOptions()[optionName]; const platformOptionValue = this._convertRulesToOptions(this._defaultOptionsRules())[optionName]; stylingModeClass = prefix + (platformOptionValue ?? defaultOptionValue) } this.$element().addClass(stylingModeClass) } _getValidationErrors() { let { validationErrors: validationErrors } = this.option(); const { validationError: validationError } = this.option(); if (!validationErrors && validationError) { validationErrors = [validationError] } return validationErrors } _disposeValidationMessage() { if (this._$validationMessage) { this._$validationMessage.remove(); this.setAria("describedby", null); this._$validationMessage = void 0; this._validationMessage = void 0 } } _toggleValidationClasses(isInvalid) { this.$element().toggleClass("dx-invalid", isInvalid); this.setAria("invalid", isInvalid || void 0) } _renderValidationState() { const { validationStatus: validationStatus, _showValidationMessage: showValidationMessage } = this.option(); const isValid = this.option("isValid") && "invalid" !== validationStatus; const validationErrors = this._getValidationErrors(); const $element = this.$element(); this._toggleValidationClasses(!isValid); if (!hasWindow() || !showValidationMessage) { return } this._disposeValidationMessage(); if (!isValid && validationErrors) { const { validationMessageMode: validationMessageMode, validationMessageOffset: validationMessageOffset, validationBoundary: validationBoundary, rtlEnabled: rtlEnabled } = this.option(); this._$validationMessage = $("<div>").appendTo($element); const validationMessageContentId = `dx-${new Guid}`; this.setAria("describedby", validationMessageContentId); this._validationMessage = new ValidationMessage(this._$validationMessage, extend({ validationErrors: validationErrors, rtlEnabled: rtlEnabled, target: this._getValidationMessageTarget(), visualContainer: $element, mode: validationMessageMode, positionSide: this._getValidationMessagePosition(), offset: validationMessageOffset, boundary: validationBoundary, contentId: validationMessageContentId }, this._options.cache("validationTooltipOptions"))); this._bindInnerWidgetOptions(this._validationMessage, "validationTooltipOptions") } } _getValidationMessagePosition() { const { validationMessagePosition: validationMessagePosition } = this.option(); return validationMessagePosition } _getValidationMessageTarget() { return this.$element() } _toggleReadOnlyState() { const { readOnly: readOnly } = this.option(); this._toggleBackspaceHandler(readOnly); this.$element().toggleClass("dx-state-readonly", !!readOnly); this._setAriaReadonly(readOnly) } _setAriaReadonly(readOnly) { this.setAria("readonly", readOnly || void 0) } _toggleBackspaceHandler(isReadOnly) { const $eventTarget = this._keyboardEventBindingTarget(); const eventName = addNamespace("keydown", "editorReadOnly"); EventsEngine.off($eventTarget, eventName); if (isReadOnly) { EventsEngine.on($eventTarget, eventName, (e => { if ("backspace" === normalizeKeyName(e)) { e.preventDefault() } })) } } _dispose() { const element = this.$element()[0]; data(element, VALIDATION_TARGET, null); clearTimeout(this.showValidationMessageTimeout); this._disposeValidationMessage(); super._dispose() } _setSubmitElementName(name) { const $submitElement = this._getSubmitElement(); if (!$submitElement) { return } if (name && name.length > 0) { $submitElement.attr("name", name) } else { $submitElement.removeAttr("name") } } _getSubmitElement() { return null } _setValidationMessageOption(_ref) { var _this$_validationMess2; let { name: name, value: value } = _ref; const optionKey = VALIDATION_MESSAGE_KEYS_MAP[String(name)] ? VALIDATION_MESSAGE_KEYS_MAP[String(name)] : name; null === (_this$_validationMess2 = this._validationMessage) || void 0 === _this$_validationMess2 || _this$_validationMess2.option(optionKey, value) } _hasActiveElement() { return false } _optionChanged(args) { var _this$_validationMess3; const { name: name, value: value, previousValue: previousValue } = args; switch (name) { case "onValueChanged": this._createValueChangeAction(); break; case "readOnly": this._toggleReadOnlyState(); this._refreshFocusState(); break; case "value": if (value != previousValue) { this.option("isDirty", this._initialValue !== value); this.validationRequest.fire({ value: value, editor: this }) } if (!this._valueChangeActionSuppressed) { this._raiseValueChangeAction(value, previousValue); this._saveValueChangeEvent(void 0) } break; case "width": super._optionChanged(args); null === (_this$_validationMess3 = this._validationMessage) || void 0 === _this$_validationMess3 || _this$_validationMess3.updateMaxWidth(); break; case "name": this._setSubmitElementName(value); break; case "isValid": case "validationError": case "validationErrors": case "validationStatus": this.option(ValidationEngine.synchronizeValidationOptions(args, this.option())); this._renderValidationState(); break; case "validationBoundary": case "validationMessageMode": case "validationMessagePosition": case "validationMessageOffset": this._setValidationMessageOption(args); break; case "rtlEnabled": this._setValidationMessageOption(args); super._optionChanged(args); break; case "validationTooltipOptions": this._innerWidgetOptionChanged(this._validationMessage, args); break; case "_showValidationMessage": case "isDirty": break; default: super._optionChanged(args) } } _resetToInitialValue() { this.option("value", this._initialValue) } blur() { if (this._hasActiveElement()) { domUtils.resetActiveElement() } } clear() { const defaultOptions = this._getDefaultOptions(); this.option("value", defaultOptions.value) } reset() { let value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : void 0; if (arguments.length) { this._initialValue = value } this._resetToInitialValue(); this.option("isDirty", false); this.option("isValid", true) } } Editor.isEditor = instance => instance instanceof Editor; export default Editor;