UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

241 lines (240 loc) • 9.15 kB
/** * DevExtreme (esm/__internal/ui/m_text_area.js) * Version: 25.2.7 * Build date: Tue May 05 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import eventsEngine from "../../common/core/events/core/events_engine"; import scrollEvents from "../../common/core/events/gesture/emitter.gesture.scroll"; import pointerEvents from "../../common/core/events/pointer"; import { addNamespace, eventData } from "../../common/core/events/utils/index"; import registerComponent from "../../core/component_registrator"; import $ from "../../core/renderer"; import { ensureDefined, noop } from "../../core/utils/common"; import { getElementBoxParams, getOuterHeight, getVerticalOffsets, parseHeight } from "../../core/utils/size"; import { isDefined } from "../../core/utils/type"; import { getWindow, hasWindow } from "../../core/utils/window"; import TextBox from "../ui/text_box/m_text_box"; import { allowScroll, prepareScrollData } from "../ui/text_box/utils.scroll"; export const TEXTAREA_CLASS = "dx-textarea"; export const TEXTEDITOR_INPUT_CLASS_AUTO_RESIZE = "dx-texteditor-input-auto-resize"; class TextArea extends TextBox { _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { spellcheck: true, autoResizeEnabled: false, _shouldAttachKeyboardEvents: false }) } _shouldAttachKeyboardEvents() { const { _shouldAttachKeyboardEvents: shouldAttachKeyboardEvents, readOnly: readOnly } = this.option(); return shouldAttachKeyboardEvents || !readOnly } _initMarkup() { this.$element().addClass("dx-textarea"); super._initMarkup(); this.setAria("multiline", "true") } _renderContentImpl() { this._updateInputHeight(); super._renderContentImpl() } _renderInput() { super._renderInput(); this._renderScrollHandler() } _createInput() { const $input = $("<textarea>"); this._applyInputAttributes($input, this.option("inputAttr")); this._updateInputAutoResizeAppearance($input); return $input } _setInputMinHeight() {} _renderScrollHandler() { this._eventY = 0; const $input = this._input(); const initScrollData = prepareScrollData($input, true); eventsEngine.on($input, addNamespace(scrollEvents.init, this.NAME), initScrollData, noop); eventsEngine.on($input, addNamespace(pointerEvents.down, this.NAME), this._pointerDownHandler.bind(this)); eventsEngine.on($input, addNamespace(pointerEvents.move, this.NAME), this._pointerMoveHandler.bind(this)) } _pointerDownHandler(e) { this._eventY = eventData(e).y } _pointerMoveHandler(e) { const currentEventY = eventData(e).y; const delta = this._eventY - currentEventY; if (allowScroll(this._input(), delta)) { e.isScrollingEvent = true; e.stopPropagation() } this._eventY = currentEventY } _renderDimensions() { const $element = this.$element(); const element = $element.get(0); const width = this._getOptionValue("width", element); const height = this._getOptionValue("height", element); const minHeight = this.option("minHeight"); const maxHeight = this.option("maxHeight"); $element.css({ minHeight: void 0 !== minHeight ? minHeight : "", maxHeight: void 0 !== maxHeight ? maxHeight : "", width: width, height: height }) } _resetDimensions() { this.$element().css({ height: "", minHeight: "", maxHeight: "" }) } _renderEvents() { if (this.option("autoResizeEnabled")) { eventsEngine.on(this._input(), addNamespace("input paste", this.NAME), this._updateInputHeight.bind(this)) } super._renderEvents() } _refreshEvents() { eventsEngine.off(this._input(), addNamespace("input paste", this.NAME)); super._refreshEvents() } _getHeightDifference($input) { var _this$_$textEditorCon, _this$_$textEditorInp; const verticalElementOffset = getVerticalOffsets(this.$element().get(0), false); const verticalEditorContainerOffset = getVerticalOffsets(null === (_this$_$textEditorCon = this._$textEditorContainer) || void 0 === _this$_$textEditorCon ? void 0 : _this$_$textEditorCon.get(0), false); const verticalInputContainerOffsets = getVerticalOffsets(null === (_this$_$textEditorInp = this._$textEditorInputContainer) || void 0 === _this$_$textEditorInp ? void 0 : _this$_$textEditorInp.get(0), true); const inputMargin = getElementBoxParams("height", getWindow().getComputedStyle($input.get(0))).margin; const sum = verticalElementOffset + verticalEditorContainerOffset + verticalInputContainerOffsets + inputMargin; return sum } _updateInputHeight() { if (!hasWindow()) { return } const { autoResizeEnabled: autoResizeEnabled, height: height, minHeight: minHeightOptionValue } = this.option(); const $input = this._input(); const shouldCalculateInputHeight = autoResizeEnabled || void 0 === height && minHeightOptionValue; if (!shouldCalculateInputHeight) { $input.css("height", ""); return } this._resetDimensions(); this.$element().css("height", getOuterHeight(this.$element())); $input.css("height", 0); const heightDifference = this._getHeightDifference($input); this._renderDimensions(); const minHeight = this._getBoundaryHeight("minHeight"); const maxHeight = this._getMaxHeight(); let inputHeight = $input[0].scrollHeight; if (void 0 !== minHeight) { inputHeight = Math.max(inputHeight, minHeight - heightDifference) } if (void 0 !== maxHeight) { const adjustedMaxHeight = this._getAdjustedMaxHeight(maxHeight, heightDifference); const needScroll = inputHeight > adjustedMaxHeight; inputHeight = Math.min(inputHeight, adjustedMaxHeight); this._updateInputAutoResizeAppearance($input, !needScroll) } $input.css("height", inputHeight); if (autoResizeEnabled) { this.$element().css("height", "auto") } } _getAdjustedMaxHeight(maxHeight, heightDifference) { const adjustedMaxHeight = maxHeight - heightDifference; return adjustedMaxHeight } _getMaxHeight() { return this._getBoundaryHeight("maxHeight") } _getBoundaryHeight(optionName) { const boundaryValue = this.option(optionName); if (isDefined(boundaryValue)) { return "number" === typeof boundaryValue ? boundaryValue : parseHeight(boundaryValue, this.$element().get(0).parentElement, this.$element().get(0)) } return } _renderInputType() {} _visibilityChanged(visible) { if (visible) { this._updateInputHeight() } } _updateInputAutoResizeAppearance($input, isAutoResizeEnabled) { if ($input) { const autoResizeEnabled = ensureDefined(isAutoResizeEnabled, Boolean(this.option("autoResizeEnabled"))); $input.toggleClass("dx-texteditor-input-auto-resize", autoResizeEnabled) } } _dimensionChanged() { if (this.option("visible")) { this._updateInputHeight() } } _optionChanged(args) { const { name: name, value: value } = args; switch (name) { case "_shouldAttachKeyboardEvents": case "autoResizeEnabled": this._updateInputAutoResizeAppearance(this._input(), Boolean(value)); this._refreshEvents(); this._renderDimensions(); this._updateInputHeight(); break; case "value": case "height": super._optionChanged(args); this._updateInputHeight(); break; case "minHeight": case "maxHeight": this._renderDimensions(); this._updateInputHeight(); break; case "visible": super._optionChanged(args); if (value) { this._updateInputHeight() } break; default: super._optionChanged(args) } } } registerComponent("dxTextArea", TextArea); export default TextArea;