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 { MediaViewerOrigin } from '../../../types';
|
||||||
|
|
||||||
import { ANIMATION_END_DELAY } from '../../../config';
|
import { ANIMATION_END_DELAY, MESSAGE_CONTENT_SELECTOR } from '../../../config';
|
||||||
import {
|
import {
|
||||||
calculateDimensions,
|
calculateDimensions,
|
||||||
getMediaViewerAvailableDimensions,
|
getMediaViewerAvailableDimensions,
|
||||||
@ -330,7 +330,7 @@ function getNodes(origin: MediaViewerOrigin, message?: ApiMessage) {
|
|||||||
case MediaViewerOrigin.Inline:
|
case MediaViewerOrigin.Inline:
|
||||||
default:
|
default:
|
||||||
containerSelector = `.Transition__slide--active > .MessageList #${getMessageHtmlId(message!.id)}`;
|
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)!;
|
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 { ApiMessage } from '../../../api/types';
|
||||||
import type { ISettings } from '../../../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 { getMessageInvoice, getWebDocumentHash } from '../../../global/helpers';
|
||||||
import { formatCurrency } from '../../../util/formatCurrency';
|
import { formatCurrency } from '../../../util/formatCurrency';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
@ -53,13 +53,13 @@ const Invoice: FC<OwnProps> = ({
|
|||||||
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
|
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
|
||||||
if (!shouldAffectAppendix) {
|
if (!shouldAffectAppendix) {
|
||||||
if (prevShouldAffectAppendix) {
|
if (prevShouldAffectAppendix) {
|
||||||
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (photoUrl) {
|
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) => {
|
getCustomAppendixBg(photoUrl, false, isInSelectMode, isSelected, theme).then((appendixBg) => {
|
||||||
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
||||||
contentEl.setAttribute(CUSTOM_APPENDIX_ATTRIBUTE, '');
|
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 { ApiChat, ApiMessage, ApiUser } from '../../../api/types';
|
||||||
import type { ISettings } from '../../../types';
|
import type { ISettings } from '../../../types';
|
||||||
|
|
||||||
import { CUSTOM_APPENDIX_ATTRIBUTE } from '../../../config';
|
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
|
||||||
import {
|
import {
|
||||||
getMessageLocation,
|
getMessageLocation,
|
||||||
buildStaticMapHash,
|
buildStaticMapHash,
|
||||||
@ -150,13 +150,13 @@ const Location: FC<OwnProps> = ({
|
|||||||
useLayoutEffectWithPrevDeps(([prevShouldRenderText]) => {
|
useLayoutEffectWithPrevDeps(([prevShouldRenderText]) => {
|
||||||
if (shouldRenderText) {
|
if (shouldRenderText) {
|
||||||
if (!prevShouldRenderText) {
|
if (!prevShouldRenderText) {
|
||||||
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapBlobUrl) {
|
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) => {
|
getCustomAppendixBg(mapBlobUrl, isOwn, isInSelectMode, isSelected, theme).then((appendixBg) => {
|
||||||
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
||||||
contentEl.classList.add('has-appendix-thumb');
|
contentEl.classList.add('has-appendix-thumb');
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import type { ISettings } from '../../../types';
|
|||||||
import type { IMediaDimensions } from './helpers/calculateAlbumLayout';
|
import type { IMediaDimensions } from './helpers/calculateAlbumLayout';
|
||||||
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
import type { ObserveFn } from '../../../hooks/useIntersectionObserver';
|
||||||
|
|
||||||
import { CUSTOM_APPENDIX_ATTRIBUTE } from '../../../config';
|
import { CUSTOM_APPENDIX_ATTRIBUTE, MESSAGE_CONTENT_SELECTOR } from '../../../config';
|
||||||
import {
|
import {
|
||||||
getMessagePhoto,
|
getMessagePhoto,
|
||||||
getMessageWebPagePhoto,
|
getMessageWebPagePhoto,
|
||||||
@ -132,12 +132,12 @@ const Photo: FC<OwnProps> = ({
|
|||||||
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
|
useLayoutEffectWithPrevDeps(([prevShouldAffectAppendix]) => {
|
||||||
if (!shouldAffectAppendix) {
|
if (!shouldAffectAppendix) {
|
||||||
if (prevShouldAffectAppendix) {
|
if (prevShouldAffectAppendix) {
|
||||||
ref.current!.closest<HTMLDivElement>('.message-content')!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!.removeAttribute(CUSTOM_APPENDIX_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentEl = ref.current!.closest<HTMLDivElement>('.message-content')!;
|
const contentEl = ref.current!.closest<HTMLDivElement>(MESSAGE_CONTENT_SELECTOR)!;
|
||||||
if (fullMediaData) {
|
if (fullMediaData) {
|
||||||
getCustomAppendixBg(fullMediaData, isOwn, isInSelectMode, isSelected, theme).then((appendixBg) => {
|
getCustomAppendixBg(fullMediaData, isOwn, isInSelectMode, isSelected, theme).then((appendixBg) => {
|
||||||
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
contentEl.style.setProperty('--appendix-bg', appendixBg);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { ApiMessage } from '../../../../api/types';
|
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';
|
import { getMessageContent } from '../../../../global/helpers';
|
||||||
|
|
||||||
export function buildContentClassName(
|
export function buildContentClassName(
|
||||||
@ -35,7 +35,7 @@ export function buildContentClassName(
|
|||||||
text, photo, video, audio, voice, document, poll, webPage, contact, location, invoice,
|
text, photo, video, audio, voice, document, poll, webPage, contact, location, invoice,
|
||||||
} = getMessageContent(message);
|
} = getMessageContent(message);
|
||||||
|
|
||||||
const classNames = ['message-content'];
|
const classNames = [MESSAGE_CONTENT_CLASS_NAME];
|
||||||
const isMedia = photo || video || location || invoice?.extendedMedia;
|
const isMedia = photo || video || location || invoice?.extendedMedia;
|
||||||
const hasText = text || location?.type === 'venue' || isGeoLiveActive;
|
const hasText = text || location?.type === 'venue' || isGeoLiveActive;
|
||||||
const isMediaWithNoText = isMedia && !hasText;
|
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 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 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
|
// 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
|
export const SAFE_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN = 1440; // px
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const useNativeCopySelectedMessages = (copyMessagesByIds: ({ messageIds }: { mes
|
|||||||
function handleCopy(e: KeyboardEvent) {
|
function handleCopy(e: KeyboardEvent) {
|
||||||
const messageIds = getMessageIdsForSelectedText();
|
const messageIds = getMessageIdsForSelectedText();
|
||||||
|
|
||||||
if (messageIds && messageIds.length > 0) {
|
if (messageIds && messageIds.length > 1) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
copyMessagesByIds({ messageIds });
|
copyMessagesByIds({ messageIds });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
|
import { MESSAGE_CONTENT_CLASS_NAME } from '../config';
|
||||||
|
|
||||||
const ELEMENT_NODE = 1;
|
const ELEMENT_NODE = 1;
|
||||||
|
|
||||||
export default function getMessageIdsForSelectedText() {
|
export default function getMessageIdsForSelectedText() {
|
||||||
const selection = window.getSelection();
|
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) {
|
if (!selectedFragments || selectedFragments.childElementCount === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -25,5 +30,17 @@ export default function getMessageIdsForSelectedText() {
|
|||||||
}
|
}
|
||||||
selectedFragments = undefined;
|
selectedFragments = undefined;
|
||||||
|
|
||||||
|
if (!shouldIncludeLastMessage) {
|
||||||
|
messageIds.pop();
|
||||||
|
}
|
||||||
|
|
||||||
return messageIds;
|
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