Message List: fix copying of selected messages with quotes (#2172)
This commit is contained in:
parent
dc2d7984a1
commit
73efaaeb1c
@ -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)!;
|
||||
|
||||
@ -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, '');
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 });
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user