diff --git a/src/components/common/WebLink.tsx b/src/components/common/WebLink.tsx index 9b685e125..bbb3f7524 100644 --- a/src/components/common/WebLink.tsx +++ b/src/components/common/WebLink.tsx @@ -46,7 +46,7 @@ const WebLink: FC = ({ siteName: domain.replace(/^www./, ''), url: url.includes('://') ? url : url.includes('@') ? `mailto:${url}` : `http://${url}`, formattedDescription: getMessageText(message) !== url - ? renderMessageSummary(lang, message, undefined, undefined, MAX_TEXT_LENGTH, true) + ? renderMessageSummary(lang, message, undefined, undefined, MAX_TEXT_LENGTH) : undefined, } as ApiWebPageWithFormatted; } diff --git a/src/components/common/helpers/renderActionMessageText.tsx b/src/components/common/helpers/renderActionMessageText.tsx index 4f14fc363..16a2e5302 100644 --- a/src/components/common/helpers/renderActionMessageText.tsx +++ b/src/components/common/helpers/renderActionMessageText.tsx @@ -6,12 +6,12 @@ import { import { LangFn } from '../../../hooks/useLang'; import { getChatTitle, - getMessageContent, getMessageSummaryText, + getMessageSummaryText, getUserFullName, } from '../../../modules/helpers'; import trimText from '../../../util/trimText'; import { formatCurrency } from '../../../util/formatCurrency'; -import { renderMessageSummary, TextPart } from './renderMessageText'; +import { TextPart, renderMessageSummary } from './renderMessageText'; import renderText from './renderText'; import UserLink from '../UserLink'; @@ -19,12 +19,12 @@ import MessageLink from '../MessageLink'; import ChatLink from '../ChatLink'; import GroupCallLink from '../GroupCallLink'; -interface ActionMessageTextOptions { - maxTextLength?: number; - asPlain?: boolean; - isEmbedded?: boolean; +interface RenderOptions { + asPlainText?: boolean; + asTextWithSpoilers?: boolean; } +const MAX_LENGTH = 32; const NBSP = '\u00A0'; export function renderActionMessageText( @@ -35,21 +35,22 @@ export function renderActionMessageText( targetUsers?: ApiUser[], targetMessage?: ApiMessage, targetChatId?: string, - options: ActionMessageTextOptions = {}, + options: RenderOptions = {}, ) { if (!message.content.action) { return []; } + const { text, translationValues, amount, currency, call, } = message.content.action; const content: TextPart[] = []; - const textOptions: ActionMessageTextOptions = { ...options, maxTextLength: 32 }; + const noLinks = options.asPlainText || options.asTextWithSpoilers; const translationKey = text === 'Chat.Service.Group.UpdatedPinnedMessage1' && !targetMessage ? 'Message.PinnedGenericMessage' : text; - let unprocessed = lang(translationKey, translationValues && translationValues.length ? translationValues : undefined); + let unprocessed = lang(translationKey, translationValues?.length ? translationValues : undefined); let processed: TextPart[]; if (unprocessed.includes('%payment_amount%')) { @@ -66,10 +67,9 @@ export function renderActionMessageText( unprocessed, '%action_origin%', actionOriginUser ? ( - (!options.isEmbedded && renderUserContent(actionOriginUser, options.asPlain)) || NBSP - + renderUserContent(actionOriginUser, noLinks) || NBSP ) : actionOriginChat ? ( - (!options.isEmbedded && renderChatContent(lang, actionOriginChat, options.asPlain)) || NBSP + renderChatContent(lang, actionOriginChat, noLinks) || NBSP ) : 'User', ); @@ -80,7 +80,7 @@ export function renderActionMessageText( unprocessed, '%target_user%', targetUsers - ? targetUsers.map((user) => renderUserContent(user, options.asPlain)).filter(Boolean as any) + ? targetUsers.map((user) => renderUserContent(user, noLinks)).filter(Boolean as any) : 'User', ); @@ -91,7 +91,7 @@ export function renderActionMessageText( unprocessed, '%message%', targetMessage - ? renderMessageContent(lang, targetMessage, textOptions) + ? renderMessageContent(lang, targetMessage, options) : 'a message', ); unprocessed = processed.pop() as string; @@ -111,12 +111,12 @@ export function renderActionMessageText( unprocessed, '%target_chat%', targetChatId - ? renderMigratedContent(targetChatId, options.asPlain) + ? renderMigratedContent(targetChatId, noLinks) : 'another chat', ); content.push(...processed); - if (options.asPlain) { + if (options.asPlainText) { return content.join('').trim(); } @@ -133,47 +133,23 @@ function renderProductContent(message: ApiMessage) { : 'a product'; } -function renderMessageContent(lang: LangFn, message: ApiMessage, options: ActionMessageTextOptions = {}) { - const { maxTextLength, isEmbedded, asPlain } = options; +function renderMessageContent(lang: LangFn, message: ApiMessage, options: RenderOptions = {}) { + const { asPlainText, asTextWithSpoilers } = options; - const text = asPlain - ? [trimText(getMessageSummaryText(lang, message), maxTextLength)] - : renderMessageSummary(lang, message, undefined, undefined, maxTextLength, true); - const { - photo, video, document, sticker, - } = getMessageContent(message); - - const showQuotes = isEmbedded && text && !photo && !video && !document && !sticker; - let messageText = text; - - if (isEmbedded) { - if (photo) { - messageText = ['a photo']; - } else if (video) { - messageText = [video.isGif ? 'a GIF' : 'a video']; - } else if (document) { - messageText = ['a document']; - } else if (sticker) { - messageText = text; - } + if (asPlainText) { + return getMessageSummaryText(lang, message, undefined, MAX_LENGTH); } - if (asPlain && messageText) { - return (showQuotes ? ['«', ...messageText, '»'] : messageText).join(''); - } + const messageSummary = renderMessageSummary(lang, message, undefined, undefined, MAX_LENGTH); - if (showQuotes) { + if (asTextWithSpoilers) { return ( - - « - {messageText} - » - + {messageSummary} ); } return ( - {messageText} + {messageSummary} ); } @@ -185,30 +161,30 @@ function renderGroupCallContent(groupCall: Partial, text: TextPart ); } -function renderUserContent(sender: ApiUser, asPlain?: boolean): string | TextPart | undefined { - const text = trimText(getUserFullName(sender)); +function renderUserContent(sender: ApiUser, noLinks?: boolean): string | TextPart | undefined { + const text = trimText(getUserFullName(sender), MAX_LENGTH); - if (asPlain) { + if (noLinks) { return text; } return {sender && renderText(text!)}; } -function renderChatContent(lang: LangFn, chat: ApiChat, asPlain?: boolean): string | TextPart | undefined { - const text = trimText(getChatTitle(lang, chat)); +function renderChatContent(lang: LangFn, chat: ApiChat, noLinks?: boolean): string | TextPart | undefined { + const text = trimText(getChatTitle(lang, chat), MAX_LENGTH); - if (asPlain) { + if (noLinks) { return text; } return {chat && renderText(text!)}; } -function renderMigratedContent(chatId: string, asPlain?: boolean): string | TextPart | undefined { +function renderMigratedContent(chatId: string, noLinks?: boolean): string | TextPart | undefined { const text = 'another chat'; - if (asPlain) { + if (noLinks) { return text; } diff --git a/src/components/common/helpers/renderMessageText.ts b/src/components/common/helpers/renderMessageText.ts new file mode 100644 index 000000000..251eaa78e --- /dev/null +++ b/src/components/common/helpers/renderMessageText.ts @@ -0,0 +1,71 @@ +import { ApiMessage, ApiMessageEntityTypes } from '../../../api/types'; +import { + getMessageSummaryDescription, + getMessageSummaryEmoji, + getMessageSummaryText, + getMessageText, + TRUNCATED_SUMMARY_LENGTH, +} from '../../../modules/helpers'; +import { LangFn } from '../../../hooks/useLang'; +import renderText from './renderText'; +import { renderTextWithEntities, TextPart } from './renderTextWithEntities'; +import trimText from '../../../util/trimText'; + +export type { TextPart }; + +export function renderMessageText( + message: ApiMessage, + highlight?: string, + shouldRenderHqEmoji?: boolean, + isSimple?: boolean, + truncateLength?: number, +) { + const { text, entities } = message.content.text || {}; + + if (!text) { + const contentNotSupportedText = getMessageText(message); + return contentNotSupportedText ? [trimText(contentNotSupportedText, truncateLength)] : undefined; + } + + return renderTextWithEntities( + trimText(text, truncateLength), + entities, + highlight, + shouldRenderHqEmoji, + undefined, + message.id, + isSimple, + ); +} + +export function renderMessageSummary( + lang: LangFn, + message: ApiMessage, + noEmoji = false, + highlight?: string, + truncateLength = TRUNCATED_SUMMARY_LENGTH, +): TextPart[] { + let { entities } = message.content.text || {}; + + const hasSpoilers = entities?.some((e) => e.type === ApiMessageEntityTypes.Spoiler); + if (!hasSpoilers) { + const text = trimText(getMessageSummaryText(lang, message, noEmoji), truncateLength); + + if (highlight) { + return renderText(text, ['emoji', 'highlight'], { highlight }); + } else { + return renderText(text); + } + } + + const emoji = !noEmoji && getMessageSummaryEmoji(message); + const emojiWithSpace = emoji ? `${emoji} ` : ''; + + const text = renderMessageText(message, highlight, undefined, true, truncateLength); + const description = getMessageSummaryDescription(lang, message, text); + + return [ + emojiWithSpace, + ...(Array.isArray(description) ? description : [description]), + ].filter(Boolean); +} diff --git a/src/components/common/helpers/renderMessageText.tsx b/src/components/common/helpers/renderTextWithEntities.tsx similarity index 86% rename from src/components/common/helpers/renderMessageText.tsx rename to src/components/common/helpers/renderTextWithEntities.tsx index 5a84df341..534d9db8a 100644 --- a/src/components/common/helpers/renderMessageText.tsx +++ b/src/components/common/helpers/renderTextWithEntities.tsx @@ -2,159 +2,23 @@ import { MouseEvent } from 'react'; import React from '../../../lib/teact/teact'; import { getDispatch } from '../../../lib/teact/teactn'; -import { ApiMessageEntity, ApiMessageEntityTypes, ApiMessage } from '../../../api/types'; - -import { - getMessageSummaryText, - getMessageSummaryDescription, - getMessageSummaryEmoji, - getMessageText, - TRUNCATED_SUMMARY_LENGTH, -} from '../../../modules/helpers'; +import { ApiFormattedText, ApiMessageEntity, ApiMessageEntityTypes } from '../../../api/types'; import renderText, { TextFilter } from './renderText'; import MentionLink from '../../middle/message/MentionLink'; import SafeLink from '../SafeLink'; import Spoiler from '../spoiler/Spoiler'; -import { LangFn } from '../../../hooks/useLang'; export type TextPart = string | Element; -export function renderMessageSummary( - lang: LangFn, - message: ApiMessage, - noEmoji = false, - highlight?: string, - truncateLength = TRUNCATED_SUMMARY_LENGTH, - shouldAddEllipsis?: boolean, -): TextPart[] { - const hasSpoilers = message.content.text?.entities?.some((l) => l.type === ApiMessageEntityTypes.Spoiler); - if (!hasSpoilers) { - let text = getMessageSummaryText(lang, message, noEmoji, truncateLength); - if (shouldAddEllipsis) { - text += '...'; - } - - if (highlight) { - return renderText(text, ['emoji', 'highlight'], { - highlight, - }); - } else { - return renderText(text); - } - } - - const text = renderMessageText(message, highlight, undefined, true, truncateLength); - const emoji = !noEmoji && getMessageSummaryEmoji(message); - const emojiWithSpace = emoji ? `${emoji} ` : ''; - const description = getMessageSummaryDescription(lang, message, text); - return [ - emojiWithSpace, - ...(Array.isArray(description) ? description : [description]), - shouldAddEllipsis && '...', - ].filter(Boolean); -} - -export function renderMessageText( - message: ApiMessage, - highlight?: string, - shouldRenderHqEmoji?: boolean, - isSimple?: boolean, - truncateLength?: number, -) { - const formattedText = message.content.text; - - if (!formattedText || !formattedText.text) { - const rawText = getMessageText(message); - return rawText ? [rawText] : undefined; - } - const { text, entities } = formattedText; - - return renderTextWithEntities( - truncateLength ? text.substr(0, truncateLength) : text, - entities, - highlight, - shouldRenderHqEmoji, - undefined, - message.id, - isSimple, - ); -} - interface IOrganizedEntity { entity: ApiMessageEntity; organizedIndexes: Set; nestedEntities: IOrganizedEntity[]; } -function organizeEntity( - entity: ApiMessageEntity, - index: number, - entities: ApiMessageEntity[], - organizedEntityIndexes: Set, -): IOrganizedEntity | undefined { - const { offset, length } = entity; - const organizedIndexes = new Set([index]); - - if (organizedEntityIndexes.has(index)) { - return undefined; - } - - // Determine any nested entities inside current entity - const nestedEntities: IOrganizedEntity[] = []; - const parsedNestedEntities = entities - .filter((e, i) => i > index && e.offset >= offset && e.offset < offset + length) - .map((e) => organizeEntity(e, entities.indexOf(e), entities, organizedEntityIndexes)) - .filter(Boolean as any); - - parsedNestedEntities.forEach((parsedEntity) => { - let isChanged = false; - - parsedEntity.organizedIndexes.forEach((organizedIndex) => { - if (!isChanged && !organizedIndexes.has(organizedIndex)) { - isChanged = true; - } - - organizedIndexes.add(organizedIndex); - }); - - if (isChanged) { - nestedEntities.push(parsedEntity); - } - }); - - return { - entity, - organizedIndexes, - nestedEntities, - }; -} - -// Organize entities in a tree-like structure to better represent how the text will be displayed -function organizeEntities(entities: ApiMessageEntity[]) { - const organizedEntityIndexes: Set = new Set(); - const organizedEntities: IOrganizedEntity[] = []; - - entities.forEach((entity, index) => { - if (organizedEntityIndexes.has(index)) { - return; - } - - const organizedEntity = organizeEntity(entity, index, entities, organizedEntityIndexes); - if (organizedEntity) { - organizedEntity.organizedIndexes.forEach((organizedIndex) => { - organizedEntityIndexes.add(organizedIndex); - }); - - organizedEntities.push(organizedEntity); - } - }); - - return organizedEntities; -} - export function renderTextWithEntities( text: string, entities?: ApiMessageEntity[], @@ -283,6 +147,128 @@ export function renderTextWithEntities( return result; } +export function getTextWithEntitiesAsHtml(formattedText?: ApiFormattedText) { + const { text, entities } = formattedText || {}; + if (!text) { + return ''; + } + + const result = renderTextWithEntities( + text, + entities, + undefined, + undefined, + true, + ); + + if (Array.isArray(result)) { + return result.join(''); + } + + return result; +} + +function renderMessagePart( + content: TextPart | TextPart[], + highlight?: string, + shouldRenderHqEmoji?: boolean, + shouldRenderAsHtml?: boolean, + isSimple?: boolean, +) { + if (Array.isArray(content)) { + const result: TextPart[] = []; + + content.forEach((c) => { + result.push(...renderMessagePart(c, highlight, shouldRenderHqEmoji, shouldRenderAsHtml, isSimple)); + }); + + return result; + } + + if (shouldRenderAsHtml) { + return renderText(content, ['escape_html', 'emoji_html', 'br_html']); + } + + const emojiFilter = shouldRenderHqEmoji ? 'hq_emoji' : 'emoji'; + + const filters: TextFilter[] = [emojiFilter]; + if (!isSimple) { + filters.push('br'); + } + + if (highlight) { + return renderText(content, filters.concat('highlight'), { highlight }); + } else { + return renderText(content, filters); + } +} + +// Organize entities in a tree-like structure to better represent how the text will be displayed +function organizeEntities(entities: ApiMessageEntity[]) { + const organizedEntityIndexes: Set = new Set(); + const organizedEntities: IOrganizedEntity[] = []; + + entities.forEach((entity, index) => { + if (organizedEntityIndexes.has(index)) { + return; + } + + const organizedEntity = organizeEntity(entity, index, entities, organizedEntityIndexes); + if (organizedEntity) { + organizedEntity.organizedIndexes.forEach((organizedIndex) => { + organizedEntityIndexes.add(organizedIndex); + }); + + organizedEntities.push(organizedEntity); + } + }); + + return organizedEntities; +} + +function organizeEntity( + entity: ApiMessageEntity, + index: number, + entities: ApiMessageEntity[], + organizedEntityIndexes: Set, +): IOrganizedEntity | undefined { + const { offset, length } = entity; + const organizedIndexes = new Set([index]); + + if (organizedEntityIndexes.has(index)) { + return undefined; + } + + // Determine any nested entities inside current entity + const nestedEntities: IOrganizedEntity[] = []; + const parsedNestedEntities = entities + .filter((e, i) => i > index && e.offset >= offset && e.offset < offset + length) + .map((e) => organizeEntity(e, entities.indexOf(e), entities, organizedEntityIndexes)) + .filter(Boolean as any); + + parsedNestedEntities.forEach((parsedEntity) => { + let isChanged = false; + + parsedEntity.organizedIndexes.forEach((organizedIndex) => { + if (!isChanged && !organizedIndexes.has(organizedIndex)) { + isChanged = true; + } + + organizedIndexes.add(organizedIndex); + }); + + if (isChanged) { + nestedEntities.push(parsedEntity); + } + }); + + return { + entity, + organizedIndexes, + nestedEntities, + }; +} + function processEntity( entity: ApiMessageEntity, entityContent: TextPart, @@ -408,55 +394,6 @@ function processEntity( } } -function renderMessagePart( - content: TextPart | TextPart[], - highlight?: string, - shouldRenderHqEmoji?: boolean, - shouldRenderAsHtml?: boolean, - isSimple?: boolean, -) { - if (Array.isArray(content)) { - const result: TextPart[] = []; - - content.forEach((c) => { - result.push(...renderMessagePart(c, highlight, shouldRenderHqEmoji, shouldRenderAsHtml, isSimple)); - }); - - return result; - } - - if (shouldRenderAsHtml) { - return renderText(content, ['escape_html', 'emoji_html', 'br_html']); - } - - const emojiFilter = shouldRenderHqEmoji ? 'hq_emoji' : 'emoji'; - - const filters: TextFilter[] = [emojiFilter]; - if (!isSimple) { - filters.push('br'); - } - - if (highlight) { - return renderText(content, filters.concat('highlight'), { highlight }); - } else { - return renderText(content, filters); - } -} - -function getLinkUrl(entityContent: string, entity: ApiMessageEntity) { - const { type, url } = entity; - return type === ApiMessageEntityTypes.TextUrl && url ? url : entityContent; -} - -function handleBotCommandClick(e: MouseEvent) { - getDispatch().sendBotCommand({ command: e.currentTarget.innerText }); -} - -function handleHashtagClick(e: MouseEvent) { - getDispatch().setLocalTextSearchQuery({ query: e.currentTarget.innerText }); - getDispatch().searchTextMessagesLocal(); -} - function processEntityAsHtml( entity: ApiMessageEntity, entityContent: TextPart, @@ -510,3 +447,17 @@ function processEntityAsHtml( return renderedContent; } } + +function getLinkUrl(entityContent: string, entity: ApiMessageEntity) { + const { type, url } = entity; + return type === ApiMessageEntityTypes.TextUrl && url ? url : entityContent; +} + +function handleBotCommandClick(e: MouseEvent) { + getDispatch().sendBotCommand({ command: e.currentTarget.innerText }); +} + +function handleHashtagClick(e: MouseEvent) { + getDispatch().setLocalTextSearchQuery({ query: e.currentTarget.innerText }); + getDispatch().searchTextMessagesLocal(); +} diff --git a/src/components/left/main/Chat.tsx b/src/components/left/main/Chat.tsx index 06c6088b2..5311ca482 100644 --- a/src/components/left/main/Chat.tsx +++ b/src/components/left/main/Chat.tsx @@ -247,6 +247,7 @@ const Chat: FC = ({ actionTargetUsers, actionTargetMessage, actionTargetChatId, + { asTextWithSpoilers: true }, )}

); diff --git a/src/components/mediaViewer/MediaViewerFooter.tsx b/src/components/mediaViewer/MediaViewerFooter.tsx index 0e78766d5..60a3b0c9f 100644 --- a/src/components/mediaViewer/MediaViewerFooter.tsx +++ b/src/components/mediaViewer/MediaViewerFooter.tsx @@ -1,10 +1,10 @@ import React, { FC, useEffect, useState } from '../../lib/teact/teact'; -import { throttle } from '../../util/schedulers'; -import { TextPart } from '../common/helpers/renderMessageText'; -import buildClassName from '../../util/buildClassName'; -import { REM } from '../common/helpers/mediaDimensions'; import { IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment'; +import { throttle } from '../../util/schedulers'; +import buildClassName from '../../util/buildClassName'; +import { TextPart } from '../common/helpers/renderMessageText'; +import { REM } from '../common/helpers/mediaDimensions'; import './MediaViewerFooter.scss'; diff --git a/src/components/middle/ActionMessage.tsx b/src/components/middle/ActionMessage.tsx index f9c30ad76..ea4f07695 100644 --- a/src/components/middle/ActionMessage.tsx +++ b/src/components/middle/ActionMessage.tsx @@ -98,7 +98,7 @@ const ActionMessage: FC = ({ targetUsers, targetMessage, targetChatId, - isEmbedded ? { isEmbedded: true } : undefined, + { asTextWithSpoilers: isEmbedded }, ); const { isContextMenuOpen, contextMenuPosition, diff --git a/src/components/middle/composer/helpers/getMessageTextAsHtml.ts b/src/components/middle/composer/helpers/getMessageTextAsHtml.ts deleted file mode 100644 index 337b8688f..000000000 --- a/src/components/middle/composer/helpers/getMessageTextAsHtml.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApiFormattedText } from '../../../../api/types'; -import { renderTextWithEntities } from '../../../common/helpers/renderMessageText'; - -export default function getMessageTextAsHtml(formattedText?: ApiFormattedText) { - const { text, entities } = formattedText || {}; - if (!text) { - return ''; - } - - const result = renderTextWithEntities( - text, - entities, - undefined, - undefined, - true, - ); - - if (Array.isArray(result)) { - return result.join(''); - } - - return result; -} diff --git a/src/components/middle/composer/hooks/useDraft.ts b/src/components/middle/composer/hooks/useDraft.ts index 0fa8922ed..b62712032 100644 --- a/src/components/middle/composer/hooks/useDraft.ts +++ b/src/components/middle/composer/hooks/useDraft.ts @@ -8,10 +8,10 @@ import usePrevious from '../../../../hooks/usePrevious'; import { debounce } from '../../../../util/schedulers'; import focusEditableElement from '../../../../util/focusEditableElement'; import parseMessageInput from '../../../../util/parseMessageInput'; -import getMessageTextAsHtml from '../helpers/getMessageTextAsHtml'; import useBackgroundMode from '../../../../hooks/useBackgroundMode'; import useBeforeUnload from '../../../../hooks/useBeforeUnload'; import { IS_TOUCH_ENV } from '../../../../util/environment'; +import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities'; // Used to avoid running debounced callbacks when chat changes. let currentChatId: string | undefined; @@ -65,7 +65,7 @@ const useDraft = ( return; } - setHtml(getMessageTextAsHtml(draft)); + setHtml(getTextWithEntitiesAsHtml(draft)); if (!IS_TOUCH_ENV) { requestAnimationFrame(() => { diff --git a/src/components/middle/composer/hooks/useEditing.ts b/src/components/middle/composer/hooks/useEditing.ts index 0ef14a61d..a980e3521 100644 --- a/src/components/middle/composer/hooks/useEditing.ts +++ b/src/components/middle/composer/hooks/useEditing.ts @@ -5,9 +5,9 @@ import { ApiMessage } from '../../../../api/types'; import { EDITABLE_INPUT_ID } from '../../../../config'; import parseMessageInput from '../../../../util/parseMessageInput'; -import getMessageTextAsHtml from '../helpers/getMessageTextAsHtml'; import focusEditableElement from '../../../../util/focusEditableElement'; import { hasMessageMedia } from '../../../../modules/helpers'; +import { getTextWithEntitiesAsHtml } from '../../../common/helpers/renderTextWithEntities'; const useEditing = ( htmlRef: { current: string }, @@ -26,7 +26,7 @@ const useEditing = ( return; } - setHtml(getMessageTextAsHtml(editedMessage.content.text)); + setHtml(getTextWithEntitiesAsHtml(editedMessage.content.text)); requestAnimationFrame(() => { const messageInput = document.getElementById(EDITABLE_INPUT_ID)!; diff --git a/src/components/middle/message/Poll.tsx b/src/components/middle/message/Poll.tsx index f47a68469..11742b994 100644 --- a/src/components/middle/message/Poll.tsx +++ b/src/components/middle/message/Poll.tsx @@ -14,7 +14,7 @@ import { } from '../../../api/types'; import renderText from '../../common/helpers/renderText'; -import { renderTextWithEntities } from '../../common/helpers/renderMessageText'; +import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities'; import { formatMediaDuration } from '../../../util/dateFormat'; import useLang, { LangFn } from '../../../hooks/useLang'; diff --git a/src/components/middle/message/SponsoredMessage.tsx b/src/components/middle/message/SponsoredMessage.tsx index 689457333..66bf7f99d 100644 --- a/src/components/middle/message/SponsoredMessage.tsx +++ b/src/components/middle/message/SponsoredMessage.tsx @@ -6,7 +6,7 @@ import { getDispatch, withGlobal } from '../../../lib/teact/teactn'; import { ApiChat, ApiSponsoredMessage, ApiUser } from '../../../api/types'; -import { renderTextWithEntities } from '../../common/helpers/renderMessageText'; +import { renderTextWithEntities } from '../../common/helpers/renderTextWithEntities'; import { selectChat, selectSponsoredMessage, selectUser } from '../../../modules/selectors'; import { getChatTitle, getUserFullName } from '../../../modules/helpers'; import renderText from '../../common/helpers/renderText'; diff --git a/src/components/ui/Notification.tsx b/src/components/ui/Notification.tsx index f3397a8b5..ca45b4c19 100644 --- a/src/components/ui/Notification.tsx +++ b/src/components/ui/Notification.tsx @@ -8,9 +8,9 @@ import React, { import { ANIMATION_END_DELAY } from '../../config'; import useShowTransition from '../../hooks/useShowTransition'; -import { TextPart } from '../common/helpers/renderMessageText'; import buildClassName from '../../util/buildClassName'; import captureEscKeyListener from '../../util/captureEscKeyListener'; +import { TextPart } from '../common/helpers/renderMessageText'; import Portal from './Portal'; diff --git a/src/modules/helpers/messageSummary.ts b/src/modules/helpers/messageSummary.ts index 6b2239d39..dec555268 100644 --- a/src/modules/helpers/messageSummary.ts +++ b/src/modules/helpers/messageSummary.ts @@ -1,8 +1,10 @@ +import type { TextPart } from '../../components/common/helpers/renderTextWithEntities'; + import { LangFn } from '../../hooks/useLang'; import { ApiMessage, ApiMessageEntityTypes } from '../../api/types'; -import type { TextPart } from '../../components/common/helpers/renderMessageText'; import { CONTENT_NOT_SUPPORTED } from '../../config'; import { getMessageText } from './messages'; +import trimText from '../../util/trimText'; const SPOILER_CHARS = ['⠺', '⠵', '⠞', '⠟']; export const TRUNCATED_SUMMARY_LENGTH = 80; @@ -15,7 +17,7 @@ export function getMessageSummaryText( ) { const emoji = !noEmoji && getMessageSummaryEmoji(message); const emojiWithSpace = emoji ? `${emoji} ` : ''; - const text = getMessageTextWithSpoilers(message)?.substr(0, truncateLength); + const text = trimText(getMessageTextWithSpoilers(message), truncateLength); const description = getMessageSummaryDescription(lang, message, text); return `${emojiWithSpace}${description}`; @@ -39,6 +41,7 @@ export function getMessageTextWithSpoilers(message: ApiMessage) { const spoiler = generateBrailleSpoiler(length); + return `${accText.substr(0, offset)}${spoiler}${accText.substr(offset + length, accText.length)}`; }, text); } diff --git a/src/util/notifications.ts b/src/util/notifications.ts index 501fc67d7..d83faf61b 100644 --- a/src/util/notifications.ts +++ b/src/util/notifications.ts @@ -287,7 +287,7 @@ function getNotificationContent(chat: ApiChat, message: ApiMessage) { actionTargetUsers, actionTargetMessage, actionTargetChatId, - { asPlain: true }, + { asPlainText: true }, ) as string; } else { const senderName = getMessageSenderName(getTranslation, chat.id, messageSender); diff --git a/src/util/trimText.ts b/src/util/trimText.ts index 20038fdf8..e92d511e8 100644 --- a/src/util/trimText.ts +++ b/src/util/trimText.ts @@ -1,9 +1,7 @@ -const DEFAULT_MAX_TEXT_LENGTH = 30; - -export default function trimText(text: string | undefined, length = DEFAULT_MAX_TEXT_LENGTH) { - if (!text || text.length <= length) { +export default function trimText(text: T, length?: number) { + if (!text || !length || text.length <= length) { return text; } - return `${text.substr(0, length)}...`; + return `${text.substring(0, length)}...`; }