devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
554 lines (551 loc) • 21 kB
JavaScript
/**
* DevExtreme (cjs/__internal/ui/chat/chat.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/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _common = require("../../../common");
var _message = _interopRequireDefault(require("../../../common/core/localization/message"));
var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator"));
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _type = require("../../../core/utils/type");
var _data_helper = _interopRequireDefault(require("../../../data_helper"));
var _conditional_invoke = require("../../core/utils/conditional_invoke");
var _widget = _interopRequireDefault(require("../../core/widget/widget"));
var _alertlist = _interopRequireDefault(require("../../ui/chat/alertlist"));
var _confirmationpopup = _interopRequireDefault(require("../../ui/chat/confirmationpopup"));
var _messagebox = _interopRequireDefault(require("../../ui/chat/messagebox"));
var _messagelist = _interopRequireDefault(require("../../ui/chat/messagelist"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function(n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) {
({}).hasOwnProperty.call(t, r) && (n[r] = t[r])
}
}
return n
}, _extends.apply(null, arguments)
}
const CHAT_CLASS = "dx-chat";
const TEXTEDITOR_INPUT_CLASS = "dx-texteditor-input";
class Chat extends _widget.default {
_getDefaultOptions() {
return _extends({}, super._getDefaultOptions(), {
showDayHeaders: true,
activeStateEnabled: true,
editing: {
allowUpdating: false,
allowDeleting: false
},
focusStateEnabled: true,
hoverStateEnabled: true,
items: [],
dataSource: null,
user: {
id: (new _common.Guid).toString()
},
dayHeaderFormat: "shortdate",
messageTemplate: null,
messageTimestampFormat: "shorttime",
alerts: [],
showAvatar: true,
showUserName: true,
showMessageTimestamp: true,
typingUsers: [],
onMessageEntered: void 0,
reloadOnChange: true,
onTypingStart: void 0,
onTypingEnd: void 0,
onMessageEditingStart: void 0,
onMessageEditCanceled: void 0,
onMessageDeleting: void 0,
onMessageDeleted: void 0
})
}
_init() {
super._init();
this._initDataController();
this._refreshDataSource();
this._createMessageEnteredAction();
this._createMessageEditingStartAction();
this._createMessageEditCanceledAction();
this._createMessageDeletingAction();
this._createMessageDeletedAction();
this._createMessageUpdatingAction();
this._createMessageUpdatedAction();
this._createTypingStartAction();
this._createTypingEndAction()
}
_dataSourceLoadErrorHandler() {
this.option("items", [])
}
_dataSourceChangedHandler(newItems, e) {
if (null !== e && void 0 !== e && e.changes) {
this._messageList._modifyByChanges(e.changes);
this._setOptionWithoutOptionChange("items", newItems.slice());
this._messageList._setOptionWithoutOptionChange("items", newItems.slice());
this._messageList._toggleEmptyView()
} else {
this.option("items", newItems.slice())
}
}
_dataSourceLoadingChangedHandler(isLoading) {
var _this$_messageList;
null === (_this$_messageList = this._messageList) || void 0 === _this$_messageList || _this$_messageList.option("isLoading", isLoading)
}
_dataSourceOptions() {
return {
paginate: false
}
}
_initMarkup() {
(0, _renderer.default)(this.element()).addClass("dx-chat");
super._initMarkup();
this._renderMessageList();
this._renderAlertList();
this._renderMessageBox();
this._updateRootAria();
this._updateMessageBoxAria()
}
_renderMessageList() {
const $messageList = (0, _renderer.default)("<div>");
this.$element().append($messageList);
this._messageList = this._createComponent($messageList, _messagelist.default, this._getMessageListOptions())
}
_getMessageListOptions() {
const {
items: items = [],
user: user,
showDayHeaders: showDayHeaders = false,
showAvatar: showAvatar = false,
showUserName: showUserName = false,
showMessageTimestamp: showMessageTimestamp = false,
dayHeaderFormat: dayHeaderFormat,
messageTimestampFormat: messageTimestampFormat,
typingUsers: typingUsers = []
} = this.option();
const isLoading = this._dataController.isLoading();
const currentUserId = null === user || void 0 === user ? void 0 : user.id;
const options = {
items: items,
currentUserId: currentUserId,
allowUpdating: message => this._allowEditAction(message),
allowDeleting: message => this._allowDeleteAction(message),
isEditActionDisabled: message => this._messageToEdit === message,
messageTemplate: this._getMessageTemplate(),
showDayHeaders: showDayHeaders,
showAvatar: showAvatar,
showUserName: showUserName,
showMessageTimestamp: showMessageTimestamp,
dayHeaderFormat: dayHeaderFormat,
messageTimestampFormat: messageTimestampFormat,
typingUsers: typingUsers,
isLoading: isLoading,
onMessageEditingStart: e => {
this._messageEditingStartHandler(e);
return () => this.focus()
},
onMessageDeleting: e => {
this._messageDeletingHandler(e)
},
onEscapeKeyPressed: () => {
this.focus()
}
};
return options
}
_allowEditAction(message) {
const {
editing: editing
} = this.option();
if (!editing) {
return false
}
const {
allowUpdating: allowUpdating
} = editing;
if ("function" === typeof allowUpdating) {
return allowUpdating({
component: this,
message: message
})
}
return allowUpdating ?? false
}
_allowDeleteAction(message) {
const {
editing: editing
} = this.option();
if (!editing) {
return false
}
const {
allowDeleting: allowDeleting
} = editing;
if ("function" === typeof allowDeleting) {
return allowDeleting({
component: this,
message: message
})
}
return allowDeleting ?? false
}
_getMessageTemplate() {
const {
messageTemplate: messageTemplate
} = this.option();
if (messageTemplate) {
return (message, $container) => {
const template = this._getTemplateByOption("messageTemplate");
template.render({
container: $container,
model: {
component: this,
message: message
}
})
}
}
return null
}
_messageEditingStartHandler(e) {
var _this$_messageEditing;
if (this._messageToEdit) {
var _this$_messageEditCan;
null === (_this$_messageEditCan = this._messageEditCanceledAction) || void 0 === _this$_messageEditCan || _this$_messageEditCan.call(this, {
message: this._messageToEdit
})
}
const messageEditingStartArgs = {
message: e.message,
cancel: false
};
null === (_this$_messageEditing = this._messageEditingStartAction) || void 0 === _this$_messageEditing || _this$_messageEditing.call(this, messageEditingStartArgs);
(0, _conditional_invoke.invokeConditionally)(messageEditingStartArgs.cancel, (() => {
this._messageBox.option("text", e.message.text);
this._messageToEdit = e.message
}))
}
_messageEditCanceledHandler() {
if (this._messageToEdit) {
var _this$_messageEditCan2;
null === (_this$_messageEditCan2 = this._messageEditCanceledAction) || void 0 === _this$_messageEditCan2 || _this$_messageEditCan2.call(this, {
message: this._messageToEdit
});
this._messageToEdit = void 0
}
}
_showDeleteConfirmationPopup(e) {
this._messageToDelete = e.message;
if (!this._deleteConfirmationPopup) {
this._deleteConfirmationPopup = new _confirmationpopup.default(this.$element(), {
onApplyButtonClick: () => {
var _this$_messageDeleted;
if (this._messageToEdit === this._messageToDelete) {
var _this$_messageEditCan3;
this._messageBox.option("text", "");
null === (_this$_messageEditCan3 = this._messageEditCanceledAction) || void 0 === _this$_messageEditCan3 || _this$_messageEditCan3.call(this, {
message: this._messageToEdit
});
this._messageToEdit = void 0
}
null === (_this$_messageDeleted = this._messageDeletedAction) || void 0 === _this$_messageDeleted || _this$_messageDeleted.call(this, {
message: this._messageToDelete
})
},
rtlEnabled: this.option().rtlEnabled,
onHidden: () => {
this._messageToDelete = void 0;
this._focusTarget()[0].focus()
}
})
}
this._deleteConfirmationPopup.show()
}
_messageDeletingHandler(e) {
var _this$_messageDeletin;
const {
message: message
} = e;
const messageDeletingArgs = {
message: message,
cancel: false
};
null === (_this$_messageDeletin = this._messageDeletingAction) || void 0 === _this$_messageDeletin || _this$_messageDeletin.call(this, messageDeletingArgs);
(0, _conditional_invoke.invokeConditionally)(messageDeletingArgs.cancel, (() => {
this._showDeleteConfirmationPopup(messageDeletingArgs)
}))
}
_messageUpdatingHandler(e) {
var _this$_messageUpdatin;
const {
text: text
} = e;
const eventArgs = {
message: this._messageToEdit,
text: text,
cancel: false
};
null === (_this$_messageUpdatin = this._messageUpdatingAction) || void 0 === _this$_messageUpdatin || _this$_messageUpdatin.call(this, eventArgs);
(0, _conditional_invoke.invokeConditionally)(eventArgs.cancel, (() => {
var _this$_messageUpdated;
this._messageBox.option("text", "");
null === (_this$_messageUpdated = this._messageUpdatedAction) || void 0 === _this$_messageUpdated || _this$_messageUpdated.call(this, eventArgs);
this._messageToEdit = void 0
}))
}
_renderAlertList() {
const $errors = (0, _renderer.default)("<div>");
this.$element().append($errors);
const {
alerts: alerts = []
} = this.option();
this._alertList = this._createComponent($errors, _alertlist.default, {
items: alerts
})
}
_renderMessageBox() {
const {
activeStateEnabled: activeStateEnabled,
focusStateEnabled: focusStateEnabled,
hoverStateEnabled: hoverStateEnabled
} = this.option();
const $messageBox = (0, _renderer.default)("<div>");
this.$element().append($messageBox);
const configuration = {
activeStateEnabled: activeStateEnabled,
focusStateEnabled: focusStateEnabled,
hoverStateEnabled: hoverStateEnabled,
onMessageEntered: e => {
this._messageEnteredHandler(e)
},
onTypingStart: e => {
this._typingStartHandler(e)
},
onTypingEnd: () => {
this._typingEndHandler()
},
onMessageEditCanceled: () => {
this._messageEditCanceledHandler()
},
onMessageUpdating: e => {
this._messageUpdatingHandler(e)
}
};
this._messageBox = this._createComponent($messageBox, _messagebox.default, configuration)
}
_updateRootAria() {
const aria = {
role: "group",
label: _message.default.format("dxChat-elementAriaLabel")
};
this.setAria(aria, this.$element())
}
_updateMessageBoxAria() {
const emptyViewId = this._messageList.getEmptyViewId();
this._messageBox.updateInputAria(emptyViewId)
}
_createMessageEnteredAction() {
this._messageEnteredAction = this._createActionByOption("onMessageEntered", {
excludeValidators: ["disabled"]
})
}
_createMessageEditingStartAction() {
this._messageEditingStartAction = this._createActionByOption("onMessageEditingStart", {
excludeValidators: ["disabled"]
})
}
_createMessageEditCanceledAction() {
this._messageEditCanceledAction = this._createActionByOption("onMessageEditCanceled", {
excludeValidators: ["disabled"]
})
}
_createMessageDeletingAction() {
this._messageDeletingAction = this._createActionByOption("onMessageDeleting", {
excludeValidators: ["disabled"]
})
}
_createMessageDeletedAction() {
this._messageDeletedAction = this._createActionByOption("onMessageDeleted", {
excludeValidators: ["disabled"]
})
}
_createMessageUpdatingAction() {
this._messageUpdatingAction = this._createActionByOption("onMessageUpdating", {
excludeValidators: ["disabled"]
})
}
_createMessageUpdatedAction() {
this._messageUpdatedAction = this._createActionByOption("onMessageUpdated", {
excludeValidators: ["disabled"]
})
}
_createTypingStartAction() {
this._typingStartAction = this._createActionByOption("onTypingStart", {
excludeValidators: ["disabled"]
})
}
_createTypingEndAction() {
this._typingEndAction = this._createActionByOption("onTypingEnd", {
excludeValidators: ["disabled"]
})
}
_messageEnteredHandler(e) {
var _this$_messageEntered;
const {
text: text,
event: event
} = e;
const {
user: user
} = this.option();
const message = {
timestamp: new Date,
author: user,
text: text
};
const dataSource = this.getDataSource();
if ((0, _type.isDefined)(dataSource)) {
dataSource.store().insert(message).done((() => {
const {
reloadOnChange: reloadOnChange
} = this.option();
if (reloadOnChange) {
dataSource.reload()
}
}))
}
null === (_this$_messageEntered = this._messageEnteredAction) || void 0 === _this$_messageEntered || _this$_messageEntered.call(this, {
message: message,
event: event
})
}
_typingStartHandler(e) {
var _this$_typingStartAct;
const {
event: event
} = e;
const {
user: user
} = this.option();
null === (_this$_typingStartAct = this._typingStartAction) || void 0 === _this$_typingStartAct || _this$_typingStartAct.call(this, {
user: user,
event: event
})
}
_typingEndHandler() {
var _this$_typingEndActio;
const {
user: user
} = this.option();
null === (_this$_typingEndActio = this._typingEndAction) || void 0 === _this$_typingEndActio || _this$_typingEndActio.call(this, {
user: user
})
}
_focusTarget() {
const $input = (0, _renderer.default)(this.element()).find(".dx-texteditor-input");
return $input
}
_optionChanged(args) {
const {
name: name,
value: value
} = args;
switch (name) {
case "activeStateEnabled":
case "focusStateEnabled":
case "hoverStateEnabled":
this._messageBox.option(name, value);
break;
case "user": {
const author = value;
this._messageList.option("currentUserId", null === author || void 0 === author ? void 0 : author.id);
break
}
case "editing":
case "reloadOnChange":
break;
case "items":
this._messageList.option(name, this.option("items"));
this._updateMessageBoxAria();
break;
case "dataSource":
this._refreshDataSource();
break;
case "alerts":
this._alertList.option("items", value ?? []);
break;
case "onMessageEntered":
this._createMessageEnteredAction();
break;
case "onMessageUpdating":
case "onMessageUpdated":
case "onMessageEditCanceled":
this._createMessageEditCanceledAction();
break;
case "onMessageEditingStart":
this._createMessageEditingStartAction();
break;
case "onMessageDeleting":
this._createMessageDeletingAction();
break;
case "onMessageDeleted":
this._createMessageDeletedAction();
break;
case "onTypingStart":
this._createTypingStartAction();
break;
case "onTypingEnd":
this._createTypingEndAction();
break;
case "showDayHeaders":
case "showAvatar":
case "showUserName":
case "showMessageTimestamp":
this._messageList.option(name, !!value);
break;
case "dayHeaderFormat":
case "messageTimestampFormat":
case "typingUsers":
this._messageList.option(name, value);
break;
case "messageTemplate":
this._messageList.option(name, this._getMessageTemplate());
break;
default:
super._optionChanged(args)
}
}
_insertNewItem(item) {
const {
items: items
} = this.option();
const newItems = [...items ?? [], item];
this.option("items", newItems)
}
renderMessage() {
let message = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
this._insertNewItem(message)
}
_dispose() {
var _this$_deleteConfirma;
null === (_this$_deleteConfirma = this._deleteConfirmationPopup) || void 0 === _this$_deleteConfirma || _this$_deleteConfirma.dispose();
super._dispose()
}
}
Chat.include(_data_helper.default);
(0, _component_registrator.default)("dxChat", Chat);
var _default = exports.default = Chat;