Message List: fix copying of selected messages with quotes (#2172)

This commit is contained in:
Alexander Zinchuk 2022-12-06 13:29:47 +01:00
parent dc2d7984a1
commit 73efaaeb1c
8 changed files with 34 additions and 15 deletions

View File

@ -2,7 +2,7 @@ import type { ApiMessage, ApiDimensions } from '../../../api/types';
import { MediaViewerOrigin } from '../../../types';
import { ANIMATION_END_DELAY } from '../../../config';
import { ANIMATION_END_DELAY, MESSAGE_CONTENT_SELECTOR } from '../../../config';
import {
calculateDimensions,
getMediaViewerAvailableDimensions,
@ -330,7 +330,7 @@ function getNodes(origin: MediaViewerOrigin, message?: ApiMessage) {
case MediaViewerOrigin.Inline:
default:
containerSelector = `.Transition__slide--active > .MessageList #${getMessageHtmlId(message!.id)}`;
mediaSelector = '.message-content .full-media, .message-content .thumbnail';
mediaSelector = `${MESSAGE_CONTENT_SELECTOR} .full-media, ${MESSAGE_CONTENT_SELECTOR} .thumbnail`;
}
const container = document.querySelector<HTMLElement>(containerSelector)!;

View File

@ -4,7 +4,7 @@ import type { FC } from '../../../lib/teact/teact';
import type { ApiMessage } from '../../../api/types';
import type { ISettings } from '../../../types';
import { CUSTOM_APPENDIX_ATTRIBUTE } from '../../../config';
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
import { getMessageInvoice, getWebDocumentHash } from '../../../global/helpers';
import { formatCurrency } from '../../../util/formatCurrency';
import renderText from '../../common/helpers/renderText';
@ -53,13 +53,13 @@ const Invoice: FC<OwnProps> = ({
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
if (!shouldAffectAppendix) {
if (prevShouldAffectAppendix) {
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
}
return;
}
if (photoUrl) {
const contentEl = ref.current!.closest<HTMLDivElement>('.message-content')!;
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
getCustomAppendixBg(photoUrl, false, isInSelectMode, isSelected, theme).then((appendixBg) => {
contentEl.style.setProperty('--appendix-bg', appendixBg);
contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');

View File

@ -7,7 +7,7 @@ import type { FC } from '../../../lib/teact/teact';
import type { ApiChat, ApiMessage, ApiUser } from '../../../api/types';
import type { ISettings } from '../../../types';
import { CUSTOM_APPENDIX_ATTRIBUTE } from '../../../config';
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
import {
getMessageLocation,
buildStaticMapHash,
@ -150,13 +150,13 @@ const Location: FC<OwnProps> = ({
useLayoutEffectWithPrevDeps(([prevShouldRenderText]) => {
if (shouldRenderText) {
if (!prevShouldRenderText) {
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
}
return;
}
if (mapBlobUrl) {
const contentEl = ref.current!.closest<HTMLDivElement>('.message-content')!;
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
getCustomAppendixBg(mapBlobUrl, isOwn, isInSelectMode, isSelected, theme).then((appendixBg) => {
contentEl.style.setProperty('--appendix-bg', appendixBg);
contentEl.classList.add('has-appendix-thumb');

View File

@ -8,7 +8,7 @@ import type { ISettings } from '../../../types';
import type { IMediaDimensions } from './helpers/calculateAlbumLayout';
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
import { CUSTOM_APPENDIX_ATTRIBUTE } from '../../../config';
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
import {
getMessagePhoto,
getMessageWebPagePhoto,
@ -132,12 +132,12 @@ const Photo: FC<OwnProps> = ({
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
if (!shouldAffectAppendix) {
if (prevShouldAffectAppendix) {
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
}
return;
}
const contentEl = ref.current!.closest<HTMLDivElement>('.message-content')!;
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
if (fullMediaData) {
getCustomAppendixBg(fullMediaData, isOwn, isInSelectMode, isSelected, theme).then((appendixBg) => {
contentEl.style.setProperty('--appendix-bg', appendixBg);

View File

@ -1,6 +1,6 @@
import type { ApiMessage } from '../../../../api/types';
import { EMOJI_SIZES } from '../../../../config';
import { EMOJI_SIZES, MESSAGE_CONTENT_CLASS_NAME } from '../../../../config';
import { getMessageContent } from '../../../../global/helpers';
export function buildContentClassName(
@ -35,7 +35,7 @@ export function buildContentClassName(
text, photo, video, audio, voice, document, poll, webPage, contact, location, invoice,
} = getMessageContent(message);
const classNames = ['message-content'];
const classNames = [MESSAGE_CONTENT_CLASS_NAME];
const isMedia = photo || video || location || invoice?.extendedMedia;
const hasText = text || location?.type === 'venue' || isGeoLiveActive;
const isMediaWithNoText = isMedia && !hasText;

View File

@ -102,6 +102,8 @@ export const EDITABLE_INPUT_MODAL_ID = 'editable-message-text-modal';
export const EDITABLE_INPUT_CSS_SELECTOR = `.messages-layout .Transition__slide--active #${EDITABLE_INPUT_ID}, .messages-layout .Transition > .to #${EDITABLE_INPUT_ID}`;
export const CUSTOM_APPENDIX_ATTRIBUTE = 'data-has-custom-appendix';
export const MESSAGE_CONTENT_CLASS_NAME = 'message-content';
export const MESSAGE_CONTENT_SELECTOR = '.message-content';
// Screen width where Pinned Message / Audio Player in the Middle Header can be safely displayed
export const SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN = 1440; // px

View File

@ -5,7 +5,7 @@ const useNativeCopySelectedMessages = (copyMessagesByIds: ({ messageIds }: { mes
function handleCopy(e: KeyboardEvent) {
const messageIds = getMessageIdsForSelectedText();
if (messageIds && messageIds.length > 0) {
if (messageIds && messageIds.length > 1) {
e.preventDefault();
copyMessagesByIds({ messageIds });
}

View File

@ -1,8 +1,13 @@
import { MESSAGE_CONTENT_CLASS_NAME } from '../config';
const ELEMENT_NODE = 1;
export default function getMessageIdsForSelectedText() {
const selection = window.getSelection();
let selectedFragments = selection && selection.rangeCount ? selection.getRangeAt(0).cloneContents() : undefined;
let selectedFragments = selection?.rangeCount ? selection.getRangeAt(0).cloneContents() : undefined;
const shouldIncludeLastMessage = selection?.focusNode && selection.focusOffset > 0
&& hasParentWithClassName(selection.focusNode, MESSAGE_CONTENT_CLASS_NAME);
if (!selectedFragments || selectedFragments.childElementCount === 0) {
return undefined;
}
@ -25,5 +30,17 @@ export default function getMessageIdsForSelectedText() {
}
selectedFragments = undefined;
if (!shouldIncludeLastMessage) {
messageIds.pop();
}
return messageIds;
}
function hasParentWithClassName(element: Node, className: string): boolean {
if (element.nodeType === ELEMENT_NODE && (element as HTMLElement).classList.contains(className)) {
return true;
}
return element.parentNode ? hasParentWithClassName(element.parentNode, className) : false;
}