UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

281 lines (280 loc) • 10.7 kB
/** * DevExtreme (esm/__internal/ui/chat/messagebox.js) * Version: 25.1.3 * Build date: Wed Jun 25 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 messageLocalization from "../../../common/core/localization/message"; import devices from "../../../core/devices"; import $ from "../../../core/renderer"; import Button from "../../../ui/button"; import DOMComponent from "../../core/widget/dom_component"; import EditingPreview from "../../ui/chat/editing_preview"; import TextArea from "../../ui/m_text_area"; export const CHAT_MESSAGEBOX_CLASS = "dx-chat-messagebox"; export const CHAT_MESSAGEBOX_INPUT_CONTAINER_CLASS = "dx-chat-messagebox-input-container"; export const CHAT_MESSAGEBOX_TEXTAREA_CLASS = "dx-chat-messagebox-textarea"; export const CHAT_MESSAGEBOX_BUTTON_CLASS = "dx-chat-messagebox-button"; export const TYPING_END_DELAY = 2e3; const ESCAPE_KEY = "escape"; const isMobile = () => "desktop" !== devices.current().deviceType; class MessageBox extends DOMComponent { _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { activeStateEnabled: true, focusStateEnabled: true, hoverStateEnabled: true, onMessageEntered: void 0, onTypingStart: void 0, onTypingEnd: void 0, onMessageEditCanceled: void 0, onMessageUpdating: void 0, text: "" }) } _init() { super._init(); this._createMessageEnteredAction(); this._createTypingStartAction(); this._createTypingEndAction() } _initMarkup() { $(this.element()).addClass("dx-chat-messagebox"); super._initMarkup(); if (this.option("text")) { this._renderEditingPreview() } this._renderInputContainer() } _renderInputContainer() { const $messageBox = $("<div>").addClass("dx-chat-messagebox-input-container").appendTo(this.element()); this._renderTextArea($messageBox); this._renderButton($messageBox) } _cancelMessageEdit() { const { onMessageEditCanceled: onMessageEditCanceled } = this.option(); this.option("text", ""); this._textArea.focus(); null === onMessageEditCanceled || void 0 === onMessageEditCanceled || onMessageEditCanceled() } _renderEditingPreview() { const $editingPreview = $("<div>").prependTo(this.element()); const { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled, text: text } = this.option(); this._editingPreview = this._createComponent($editingPreview, EditingPreview, { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled, text: text, onCancel: () => this._cancelMessageEdit() }) } _renderTextArea($parent) { const { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled } = this.option(); const $textArea = $("<div>").addClass("dx-chat-messagebox-textarea"); $parent.append($textArea); this._textArea = this._createComponent($textArea, TextArea, { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled, stylingMode: "outlined", placeholder: messageLocalization.format("dxChat-textareaPlaceholder"), autoResizeEnabled: true, valueChangeEvent: "input", maxHeight: "8em", onInput: e => { const shouldButtonBeDisabled = !this._isValuableTextEntered(); this._toggleButtonDisableState(shouldButtonBeDisabled); this._triggerTypingStartAction(e); this._updateTypingEndTimeout() }, onEnterKey: e => { var _e$event; if (isMobile()) { return } if (!(null !== (_e$event = e.event) && void 0 !== _e$event && _e$event.shiftKey)) { this._sendHandler(e) } } }); this._textArea.registerKeyHandler("enter", (event => { if (!event.shiftKey && this._isValuableTextEntered() && !isMobile()) { event.preventDefault() } })); this._textArea.registerKeyHandler("escape", (() => { if (this.option("text")) { this._cancelMessageEdit() } })) } _renderButton($parent) { const { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled } = this.option(); const $button = $("<div>").addClass("dx-chat-messagebox-button"); $parent.append($button); this._button = this._createComponent($button, Button, { activeStateEnabled: activeStateEnabled, focusStateEnabled: focusStateEnabled, hoverStateEnabled: hoverStateEnabled, icon: "sendfilled", type: "default", stylingMode: "text", disabled: true, elementAttr: { "aria-label": messageLocalization.format("dxChat-sendButtonAriaLabel") }, onClick: e => { this._sendHandler(e) } }) } _createMessageEnteredAction() { this._messageEnteredAction = this._createActionByOption("onMessageEntered", { excludeValidators: ["disabled"] }) } _createTypingStartAction() { this._typingStartAction = this._createActionByOption("onTypingStart", { excludeValidators: ["disabled"] }) } _createTypingEndAction() { this._typingEndAction = this._createActionByOption("onTypingEnd", { excludeValidators: ["disabled"] }) } _triggerTypingStartAction(e) { if (!this._typingEndTimeoutId) { var _this$_typingStartAct; null === (_this$_typingStartAct = this._typingStartAction) || void 0 === _this$_typingStartAct || _this$_typingStartAct.call(this, { event: e.event }) } } _updateTypingEndTimeout() { clearTimeout(this._typingEndTimeoutId); this._typingEndTimeoutId = setTimeout((() => { var _this$_typingEndActio; null === (_this$_typingEndActio = this._typingEndAction) || void 0 === _this$_typingEndActio || _this$_typingEndActio.call(this); this._clearTypingEndTimeout() }), 2e3) } _clearTypingEndTimeout() { clearTimeout(this._typingEndTimeoutId); this._typingEndTimeoutId = void 0 } _sendHandler(e) { var _this$_typingEndActio2, _this$_messageEntered; if (!this._isValuableTextEntered()) { return } this._clearTypingEndTimeout(); null === (_this$_typingEndActio2 = this._typingEndAction) || void 0 === _this$_typingEndActio2 || _this$_typingEndActio2.call(this); const { text: text = "" } = this._textArea.option(); const { text: previewText } = this.option(); if (previewText) { const { onMessageUpdating: onMessageUpdating } = this.option(); null === onMessageUpdating || void 0 === onMessageUpdating || onMessageUpdating({ text: text }); return } this._textArea.reset(); this._toggleButtonDisableState(true); null === (_this$_messageEntered = this._messageEnteredAction) || void 0 === _this$_messageEntered || _this$_messageEntered.call(this, { text: text, event: e.event }) } _toggleButtonDisableState(state) { this._button.option("disabled", state) } _isValuableTextEntered() { const { text: text } = this._textArea.option(); return !!(null !== text && void 0 !== text && text.trim()) } _optionChanged(args) { const { name: name, value: value } = args; switch (name) { case "activeStateEnabled": case "focusStateEnabled": case "hoverStateEnabled": var _this$_editingPreview; this._button.option(name, value); this._textArea.option(name, value); null === (_this$_editingPreview = this._editingPreview) || void 0 === _this$_editingPreview || _this$_editingPreview.option(name, value); break; case "onMessageEntered": this._createMessageEnteredAction(); break; case "onTypingStart": this._createTypingStartAction(); break; case "onTypingEnd": this._createTypingEndAction(); break; case "text": this._updateEditingPreview(value); this._updateInputContainer(value); break; default: super._optionChanged(args) } } _clean() { this._clearTypingEndTimeout(); super._clean() } updateInputAria(emptyViewId) { this._textArea.option({ inputAttr: { "aria-labelledby": emptyViewId } }) } _updateEditingPreview(text) { if (this._editingPreview) { this._editingPreview.option("text", text); if (!text) { this._editingPreview = null } } else { this._renderEditingPreview() } } _updateInputContainer(value) { this._textArea.option("value", value); const shouldButtonBeDisabled = !this._isValuableTextEntered(); this._toggleButtonDisableState(shouldButtonBeDisabled) } } export default MessageBox;