UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

250 lines (249 loc) • 10.5 kB
/** * DevExtreme (esm/__internal/ui/chat/messagegroup.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 dateLocalization from "../../../common/core/localization/date"; import messageLocalization from "../../../common/core/localization/message"; import $ from "../../../core/renderer"; import dateSerialization from "../../../core/utils/date_serialization"; import { isDate, isDefined } from "../../../core/utils/type"; import Widget from "../../core/widget/widget"; import Avatar from "./avatar"; import MessageBubble, { CHAT_MESSAGEBUBBLE_CLASS, MESSAGE_DATA_KEY } from "./messagebubble"; export const CHAT_MESSAGEGROUP_CLASS = "dx-chat-messagegroup"; export const CHAT_MESSAGEGROUP_ALIGNMENT_START_CLASS = "dx-chat-messagegroup-alignment-start"; export const CHAT_MESSAGEGROUP_ALIGNMENT_END_CLASS = "dx-chat-messagegroup-alignment-end"; const CHAT_MESSAGEGROUP_INFORMATION_CLASS = "dx-chat-messagegroup-information"; const CHAT_MESSAGEGROUP_TIME_CLASS = "dx-chat-messagegroup-time"; const CHAT_MESSAGEGROUP_AUTHOR_NAME_CLASS = "dx-chat-messagegroup-author-name"; const CHAT_MESSAGEGROUP_CONTENT_CLASS = "dx-chat-messagegroup-content"; const CHAT_MESSAGE_EDITED_CLASS = "dx-chat-message-edited"; const CHAT_MESSAGE_EDITED_HIDING_CLASS = "dx-chat-message-edited-hiding"; const CHAT_MESSAGE_EDITED_ICON_CLASS = "dx-chat-message-edited-icon"; const CHAT_MESSAGE_EDITED_TEXT_CLASS = "dx-chat-message-edited-text"; class MessageGroup extends Widget { _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { items: [], alignment: "start", showAvatar: true, showUserName: true, showMessageTimestamp: true, messageTemplate: null, messageTimestampFormat: "shorttime" }) } _updateAlignmentClass() { $(this.element()).removeClass("dx-chat-messagegroup-alignment-start").removeClass("dx-chat-messagegroup-alignment-end"); const alignmentClass = this._isAlignmentStart() ? "dx-chat-messagegroup-alignment-start" : "dx-chat-messagegroup-alignment-end"; $(this.element()).addClass(alignmentClass) } _initMarkup() { const { items: items, showAvatar: showAvatar } = this.option(); $(this.element()).addClass("dx-chat-messagegroup"); this._updateAlignmentClass(); super._initMarkup(); if (0 === items.length) { return } if (showAvatar && this._isAlignmentStart()) { this._renderAvatar() } this._renderMessageGroupInformation(null === items || void 0 === items ? void 0 : items[0]); this._renderMessageBubbles(items) } _renderAvatar() { const $avatar = $("<div>").appendTo(this.element()); const { items: items } = this.option(); const { author: author } = items[0]; const authorName = null === author || void 0 === author ? void 0 : author.name; const authorAvatarUrl = null === author || void 0 === author ? void 0 : author.avatarUrl; const authorAvatarAlt = null === author || void 0 === author ? void 0 : author.avatarAlt; this._avatar = this._createComponent($avatar, Avatar, { name: authorName, url: authorAvatarUrl, alt: authorAvatarAlt }) } _renderMessageBubble(message) { const $bubble = $("<div>").data(MESSAGE_DATA_KEY, message); this._createComponent($bubble, MessageBubble, this._getMessageBubbleOptions(message)); this._$messageBubbleContainer.append($bubble) } _getMessageBubbleOptions(message) { const options = { isDeleted: message.isDeleted, type: message.type }; const { messageTemplate: messageTemplate } = this.option(); if ("image" === message.type) { options.alt = message.alt; options.src = message.src } else { options.text = message.text } if (messageTemplate) { options.template = (messageData, container) => { messageTemplate(_extends({}, message, messageData), container) } } return options } _renderMessageBubbles(items) { this._$messageBubbleContainer = $("<div>").addClass("dx-chat-messagegroup-content"); items.forEach(((message, index) => { const shouldCreateEditedElement = 0 !== index && "image" !== message.type && true === message.isEdited && !message.isDeleted; if (shouldCreateEditedElement) { const $edited = this._createEditedElement(); $edited.appendTo(this._$messageBubbleContainer) } this._renderMessageBubble(message) })); this._$messageBubbleContainer.appendTo(this.element()) } _renderMessageGroupInformation(message, shouldRenderEditedMessage) { const { showUserName: showUserName, showMessageTimestamp: showMessageTimestamp } = this.option(); const { timestamp: timestamp, author: author } = message; const isEdited = isDefined(shouldRenderEditedMessage) ? shouldRenderEditedMessage : "image" !== message.type && message.isEdited; const isAlignmentStart = this._isAlignmentStart(); this.$element().find(".dx-chat-messagegroup-information").remove(); const $information = $("<div>").addClass("dx-chat-messagegroup-information"); if (showUserName) { const authorName = (null === author || void 0 === author ? void 0 : author.name) ?? messageLocalization.format("dxChat-defaultUserName"); const authorNameText = isAlignmentStart ? authorName : ""; $("<div>").addClass("dx-chat-messagegroup-author-name").text(authorNameText).appendTo($information) } if (isEdited && !isAlignmentStart) { $information.append(this._createEditedElement()) } if (showMessageTimestamp) { const $time = $("<div>").addClass("dx-chat-messagegroup-time").appendTo($information); const shouldAddTimeValue = this._shouldAddTimeValue(timestamp); if (shouldAddTimeValue) { const timeValue = this._getTimeValue(timestamp); $time.text(timeValue) } } if (isEdited && isAlignmentStart) { $information.append(this._createEditedElement()) } $information.appendTo(this.element()) } _createEditedElement() { const $edited = $("<div>").addClass("dx-chat-message-edited"); $("<div>").addClass("dx-chat-message-edited-icon").appendTo($edited); const editedMessageText = messageLocalization.format("dxChat-editedMessageText"); $("<div>").addClass("dx-chat-message-edited-text").text(editedMessageText).appendTo($edited); return $edited } _updateMessageEditedText($message) { let isEdited = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : false; const $firstMessage = this._$messageBubbleContainer.find(`.${CHAT_MESSAGEBUBBLE_CLASS}`).first(); const removeWithAnimation = $editedElement => { $editedElement.get(0).addEventListener("animationend", (() => { $editedElement.remove() }), { once: true }); $editedElement.addClass("dx-chat-message-edited-hiding") }; if ($message.is($firstMessage)) { const items = this.option("items"); const $information = this.$element().find(".dx-chat-messagegroup-information"); const $edited = $information.find(".dx-chat-message-edited"); if ($edited.length && isEdited) { return } if ($edited.length && !isEdited) { removeWithAnimation($edited); return } if (isEdited) { this._renderMessageGroupInformation(items[0], true) } return } const $prevElement = $message.prev(); if ($prevElement.hasClass("dx-chat-message-edited")) { if (!isEdited) { removeWithAnimation($prevElement) } return } if (isEdited) { const $edited = this._createEditedElement(); $edited.insertBefore($message) } } _isAlignmentStart() { const { alignment: alignment } = this.option(); return "start" === alignment } _shouldAddTimeValue(timestamp) { const deserializedDate = dateSerialization.deserializeDate(timestamp); return isDate(deserializedDate) && !isNaN(deserializedDate.getTime()) } _getTimeValue(timestamp) { const deserializedDate = dateSerialization.deserializeDate(timestamp); const { messageTimestampFormat: messageTimestampFormat } = this.option(); const formattedTime = dateLocalization.format(deserializedDate, messageTimestampFormat); return formattedTime } _optionChanged(args) { const { name: name } = args; switch (name) { case "items": case "alignment": case "showAvatar": case "showUserName": case "showMessageTimestamp": case "messageTemplate": case "messageTimestampFormat": this._invalidate(); break; default: super._optionChanged(args) } } renderMessage(message) { const { items: items } = this.option(); const newItems = [...items, message]; this._setOptionWithoutOptionChange("items", newItems); this._renderMessageBubble(message) } } export default MessageGroup;