mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-05-14 21:37:46 +00:00
The display name is used in messages when messages are coming from visitors or from the history. The display name is used only when the participant is not available in the meeting to get its name.
286 lines
9.4 KiB
TypeScript
286 lines
9.4 KiB
TypeScript
// @ts-expect-error
|
|
import aliases from 'react-emoji-render/data/aliases';
|
|
// eslint-disable-next-line lines-around-comment
|
|
// @ts-expect-error
|
|
import emojiAsciiAliases from 'react-emoji-render/data/asciiAliases';
|
|
|
|
import { IReduxState } from '../app/types';
|
|
import { getLocalizedDateFormatter } from '../base/i18n/dateUtil';
|
|
import i18next from '../base/i18n/i18next';
|
|
import { MEET_FEATURES } from '../base/jwt/constants';
|
|
import { isJwtFeatureEnabled } from '../base/jwt/functions';
|
|
import { getParticipantById, isPrivateChatEnabled } from '../base/participants/functions';
|
|
import { IParticipant } from '../base/participants/types';
|
|
import { escapeRegexp } from '../base/util/helpers';
|
|
import { getParticipantsPaneWidth } from '../participants-pane/functions';
|
|
import { VIDEO_SPACE_MIN_SIZE } from '../video-layout/constants';
|
|
import { IVisitorChatParticipant } from '../visitors/types';
|
|
|
|
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL, TIMESTAMP_FORMAT } from './constants';
|
|
import { IMessage } from './types';
|
|
|
|
/**
|
|
* An ASCII emoticon regexp array to find and replace old-style ASCII
|
|
* emoticons (such as :O) with the new Unicode representation, so that
|
|
* devices and browsers that support them can render these natively
|
|
* without a 3rd party component.
|
|
*
|
|
* NOTE: this is currently only used on mobile, but it can be used
|
|
* on web too once we drop support for browsers that don't support
|
|
* unicode emoji rendering.
|
|
*/
|
|
const ASCII_EMOTICON_REGEXP_ARRAY: Array<[RegExp, string]> = [];
|
|
|
|
/**
|
|
* An emoji regexp array to find and replace alias emoticons
|
|
* (such as :smiley:) with the new Unicode representation, so that
|
|
* devices and browsers that support them can render these natively
|
|
* without a 3rd party component.
|
|
*
|
|
* NOTE: this is currently only used on mobile, but it can be used
|
|
* on web too once we drop support for browsers that don't support
|
|
* unicode emoji rendering.
|
|
*/
|
|
const SLACK_EMOJI_REGEXP_ARRAY: Array<[RegExp, string]> = [];
|
|
|
|
(function() {
|
|
for (const [ key, value ] of Object.entries(aliases)) {
|
|
|
|
// Add ASCII emoticons
|
|
const asciiEmoticons = emojiAsciiAliases[key];
|
|
|
|
if (asciiEmoticons) {
|
|
const asciiEscapedValues = asciiEmoticons.map((v: string) => escapeRegexp(v));
|
|
|
|
const asciiRegexp = `(${asciiEscapedValues.join('|')})`;
|
|
|
|
// Escape urls
|
|
const formattedAsciiRegexp = key === 'confused'
|
|
? `(?=(${asciiRegexp}))(:(?!//).)`
|
|
: asciiRegexp;
|
|
|
|
ASCII_EMOTICON_REGEXP_ARRAY.push([ new RegExp(formattedAsciiRegexp, 'g'), value as string ]);
|
|
}
|
|
|
|
// Add slack-type emojis
|
|
const emojiRegexp = `\\B(${escapeRegexp(`:${key}:`)})\\B`;
|
|
|
|
SLACK_EMOJI_REGEXP_ARRAY.push([ new RegExp(emojiRegexp, 'g'), value as string ]);
|
|
}
|
|
})();
|
|
|
|
/**
|
|
* Replaces ASCII and other non-unicode emoticons with unicode emojis to let the emojis be rendered
|
|
* by the platform native renderer.
|
|
*
|
|
* @param {string} message - The message to parse and replace.
|
|
* @returns {string}
|
|
*/
|
|
export function replaceNonUnicodeEmojis(message: string): string {
|
|
let replacedMessage = message;
|
|
|
|
for (const [ regexp, replaceValue ] of SLACK_EMOJI_REGEXP_ARRAY) {
|
|
replacedMessage = replacedMessage.replace(regexp, replaceValue);
|
|
}
|
|
|
|
for (const [ regexp, replaceValue ] of ASCII_EMOTICON_REGEXP_ARRAY) {
|
|
replacedMessage = replacedMessage.replace(regexp, replaceValue);
|
|
}
|
|
|
|
return replacedMessage;
|
|
}
|
|
|
|
/**
|
|
* Selector for calculating the number of unread chat messages.
|
|
*
|
|
* @param {IReduxState} state - The redux state.
|
|
* @returns {number} The number of unread messages.
|
|
*/
|
|
export function getUnreadCount(state: IReduxState) {
|
|
const { lastReadMessage, messages } = state['features/chat'];
|
|
const messagesCount = messages.length;
|
|
|
|
if (!messagesCount) {
|
|
return 0;
|
|
}
|
|
|
|
let reactionMessages = 0;
|
|
let lastReadIndex: number;
|
|
|
|
if (navigator.product === 'ReactNative') {
|
|
// React native stores the messages in a reversed order.
|
|
lastReadIndex = messages.indexOf(<IMessage>lastReadMessage);
|
|
|
|
for (let i = 0; i < lastReadIndex; i++) {
|
|
if (messages[i].isReaction) {
|
|
reactionMessages++;
|
|
}
|
|
}
|
|
|
|
return lastReadIndex - reactionMessages;
|
|
}
|
|
|
|
lastReadIndex = messages.lastIndexOf(<IMessage>lastReadMessage);
|
|
|
|
for (let i = lastReadIndex + 1; i < messagesCount; i++) {
|
|
if (messages[i].isReaction) {
|
|
reactionMessages++;
|
|
}
|
|
}
|
|
|
|
return messagesCount - (lastReadIndex + 1) - reactionMessages;
|
|
}
|
|
|
|
/**
|
|
* Get whether the chat smileys are disabled or not.
|
|
*
|
|
* @param {IReduxState} state - The redux state.
|
|
* @returns {boolean} The disabled flag.
|
|
*/
|
|
export function areSmileysDisabled(state: IReduxState) {
|
|
const disableChatSmileys = state['features/base/config']?.disableChatSmileys === true;
|
|
|
|
return disableChatSmileys;
|
|
}
|
|
|
|
/**
|
|
* Returns the timestamp to display for the message.
|
|
*
|
|
* @param {IMessage} message - The message from which to get the timestamp.
|
|
* @returns {string}
|
|
*/
|
|
export function getFormattedTimestamp(message: IMessage) {
|
|
return getLocalizedDateFormatter(new Date(message.timestamp))
|
|
.format(TIMESTAMP_FORMAT);
|
|
}
|
|
|
|
/**
|
|
* Generates the message text to be rendered in the component.
|
|
*
|
|
* @param {IMessage} message - The message from which to get the text.
|
|
* @returns {string}
|
|
*/
|
|
export function getMessageText(message: IMessage) {
|
|
return message.messageType === MESSAGE_TYPE_ERROR
|
|
? i18next.t('chat.error', {
|
|
error: message.message
|
|
})
|
|
: message.message;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns whether a message can be replied to.
|
|
*
|
|
* @param {IReduxState} state - The redux state.
|
|
* @param {IMessage} message - The message to be checked.
|
|
* @returns {boolean}
|
|
*/
|
|
export function getCanReplyToMessage(state: IReduxState, message: IMessage) {
|
|
const { knocking } = state['features/lobby'];
|
|
const participant = getParticipantById(state, message.participantId);
|
|
|
|
// Check if basic reply conditions are met
|
|
const basicCanReply = (Boolean(participant) || message.isFromVisitor)
|
|
&& (message.privateMessage || (message.lobbyChat && !knocking))
|
|
&& message.messageType !== MESSAGE_TYPE_LOCAL;
|
|
|
|
if (!basicCanReply) {
|
|
return false;
|
|
}
|
|
|
|
// Check private chat configuration for visitor messages
|
|
if (message.isFromVisitor) {
|
|
const visitorParticipant = { id: message.participantId, name: message.displayName, isVisitor: true as const };
|
|
|
|
return isPrivateChatEnabled(visitorParticipant, state);
|
|
}
|
|
|
|
// For non-visitor messages, use the regular participant
|
|
return isPrivateChatEnabled(participant, state);
|
|
}
|
|
|
|
/**
|
|
* Returns the message that is displayed as a notice for private messages.
|
|
*
|
|
* @param {IMessage} message - The message to be checked.
|
|
* @returns {string}
|
|
*/
|
|
export function getPrivateNoticeMessage(message: IMessage) {
|
|
let recipient;
|
|
|
|
if (message.messageType === MESSAGE_TYPE_LOCAL) {
|
|
// For messages sent by local user, show the recipient name
|
|
// For visitor messages, use the visitor's display name with indicator
|
|
recipient = message.sentToVisitor ? `${message.recipient} ${i18next.t('visitors.chatIndicator')}` : message.recipient;
|
|
} else {
|
|
// For messages received from others, show "you"
|
|
recipient = i18next.t('chat.you');
|
|
}
|
|
|
|
return i18next.t('chat.privateNotice', {
|
|
recipient
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if participant is not allowed to send group messages.
|
|
*
|
|
* @param {IReduxState} state - The redux state.
|
|
* @returns {boolean} - Returns true if the participant is not allowed to send group messages.
|
|
*/
|
|
export function isSendGroupChatDisabled(state: IReduxState) {
|
|
const { groupChatRequiresPermission } = state['features/dynamic-branding'];
|
|
|
|
if (!groupChatRequiresPermission) {
|
|
return false;
|
|
}
|
|
|
|
return !isJwtFeatureEnabled(state, MEET_FEATURES.SEND_GROUPCHAT, false);
|
|
}
|
|
|
|
/**
|
|
* Calculates the maximum width available for the chat panel based on the current window size
|
|
* and other UI elements.
|
|
*
|
|
* @param {IReduxState} state - The Redux state containing the application's current state.
|
|
* @returns {number} The maximum width in pixels available for the chat panel. Returns 0 if there
|
|
* is no space available.
|
|
*/
|
|
export function getChatMaxSize(state: IReduxState) {
|
|
const { clientWidth } = state['features/base/responsive-ui'];
|
|
|
|
return Math.max(clientWidth - getParticipantsPaneWidth(state) - VIDEO_SPACE_MIN_SIZE, 0);
|
|
}
|
|
|
|
/**
|
|
* Type guard to check if a participant is a visitor chat participant.
|
|
*
|
|
* @param {IParticipant | IVisitorChatParticipant | undefined} participant - The participant to check.
|
|
* @returns {boolean} - True if the participant is a visitor chat participant.
|
|
*/
|
|
export function isVisitorChatParticipant(
|
|
participant?: IParticipant | IVisitorChatParticipant
|
|
): participant is IVisitorChatParticipant {
|
|
return Boolean(participant && 'isVisitor' in participant && participant.isVisitor === true);
|
|
}
|
|
|
|
/**
|
|
* Returns a suffix to be appended to the display name based on the message origin.
|
|
*
|
|
* @param {IMessage} message - The message.
|
|
* @returns {string} The suffix, if any.
|
|
*/
|
|
export function getDisplayNameSuffix(message: IMessage): string {
|
|
let suffix = '';
|
|
|
|
if (message.isFromVisitor) {
|
|
suffix = ` ${i18next.t('visitors.chatIndicator')}`;
|
|
} else if (message.isFromGuest) {
|
|
suffix = ` ${i18next.t('chat.guestsChatIndicator')}`;
|
|
}
|
|
|
|
return suffix;
|
|
}
|