Message Context Menu: Fix message link copying in Safari (#4530)
This commit is contained in:
parent
6def917d1c
commit
209564ca6f
@ -397,7 +397,13 @@ const MessageContextMenu: FC<OwnProps> = ({
|
||||
<MenuItem icon="web" onClick={onSelectLanguage}>{lang('lng_settings_change_lang')}</MenuItem>
|
||||
)}
|
||||
{copyOptions.map((option) => (
|
||||
<MenuItem key={option.label} icon={option.icon} onClick={option.handler}>{lang(option.label)}</MenuItem>
|
||||
<MenuItem
|
||||
key={option.label}
|
||||
icon={option.icon}
|
||||
onClick={option.handler}
|
||||
withPreventDefaultOnMouseDown
|
||||
>{lang(option.label)}
|
||||
</MenuItem>
|
||||
))}
|
||||
{canPin && <MenuItem icon="pin" onClick={onPin}>{lang('DialogPin')}</MenuItem>}
|
||||
{canUnpin && <MenuItem icon="unpin" onClick={onUnpin}>{lang('DialogUnpin')}</MenuItem>}
|
||||
|
||||
@ -27,6 +27,7 @@ export type MenuItemProps = {
|
||||
destructive?: boolean;
|
||||
ariaLabel?: string;
|
||||
withWrap?: boolean;
|
||||
withPreventDefaultOnMouseDown?: boolean;
|
||||
};
|
||||
|
||||
const MenuItem: FC<MenuItemProps> = (props) => {
|
||||
@ -45,6 +46,7 @@ const MenuItem: FC<MenuItemProps> = (props) => {
|
||||
withWrap,
|
||||
onContextMenu,
|
||||
clickArg,
|
||||
withPreventDefaultOnMouseDown,
|
||||
} = props;
|
||||
|
||||
const lang = useLang();
|
||||
@ -74,6 +76,11 @@ const MenuItem: FC<MenuItemProps> = (props) => {
|
||||
|
||||
onClick(e, clickArg);
|
||||
});
|
||||
const handleMouseDown = useLastCallback((e: React.SyntheticEvent<HTMLDivElement | HTMLAnchorElement>) => {
|
||||
if (withPreventDefaultOnMouseDown) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
const fullClassName = buildClassName(
|
||||
'MenuItem',
|
||||
@ -110,6 +117,7 @@ const MenuItem: FC<MenuItemProps> = (props) => {
|
||||
rel="noopener noreferrer"
|
||||
dir={lang.isRtl ? 'rtl' : undefined}
|
||||
onClick={onClick}
|
||||
onMouseDown={handleMouseDown}
|
||||
>
|
||||
{content}
|
||||
</a>
|
||||
@ -123,6 +131,7 @@ const MenuItem: FC<MenuItemProps> = (props) => {
|
||||
className={fullClassName}
|
||||
onClick={handleClick}
|
||||
onKeyDown={handleKeyDown}
|
||||
onMouseDown={handleMouseDown}
|
||||
onContextMenu={onContextMenu}
|
||||
aria-label={ariaLabel}
|
||||
title={ariaLabel}
|
||||
|
||||
@ -33,7 +33,7 @@ import {
|
||||
SUPPORTED_IMAGE_CONTENT_TYPES,
|
||||
SUPPORTED_VIDEO_CONTENT_TYPES,
|
||||
} from '../../../config';
|
||||
import { copyTextToClipboard } from '../../../util/clipboard';
|
||||
import { copyTextToClipboardFromPromise } from '../../../util/clipboard';
|
||||
import { isDeepLink } from '../../../util/deepLinkParser';
|
||||
import { ensureProtocol } from '../../../util/ensureProtocol';
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
@ -1962,35 +1962,25 @@ addActionHandler('copyMessageLink', async (global, actions, payload): Promise<vo
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isChatChannel(chat) && !isChatSuperGroup(chat)) {
|
||||
actions.showNotification({
|
||||
message: translate('lng_filters_link_private_error'),
|
||||
tabId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const link = await callApi('exportMessageLink', {
|
||||
chat,
|
||||
id: messageId,
|
||||
shouldIncludeThread,
|
||||
shouldIncludeGrouped,
|
||||
const showErrorOccurredNotification = () => actions.showNotification({
|
||||
message: translate('ErrorOccurred'),
|
||||
tabId,
|
||||
});
|
||||
|
||||
if (!link) {
|
||||
actions.showNotification({
|
||||
message: translate('ErrorOccurred'),
|
||||
tabId,
|
||||
});
|
||||
if (!isChatChannel(chat) && !isChatSuperGroup(chat)) {
|
||||
showErrorOccurredNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
copyTextToClipboard(link);
|
||||
actions.showNotification({
|
||||
const showLinkCopiedNotification = () => actions.showNotification({
|
||||
message: translate('LinkCopied'),
|
||||
tabId,
|
||||
});
|
||||
const callApiExportMessageLinkPromise = callApi('exportMessageLink', {
|
||||
chat, id: messageId, shouldIncludeThread, shouldIncludeGrouped,
|
||||
});
|
||||
await copyTextToClipboardFromPromise(
|
||||
callApiExportMessageLinkPromise, showLinkCopiedNotification, showErrorOccurredNotification,
|
||||
);
|
||||
});
|
||||
|
||||
function countSortedIds(ids: number[], from: number, to: number) {
|
||||
|
||||
@ -59,6 +59,51 @@ export const copyImageToClipboard = (imageUrl?: string) => {
|
||||
imageEl.src = imageUrl;
|
||||
};
|
||||
|
||||
export const copyTextToClipboardFromPromise = async (
|
||||
getTextPromise: Promise<string | undefined>,
|
||||
onSuccess: NoneToVoidFunction,
|
||||
onFailure: NoneToVoidFunction,
|
||||
) => {
|
||||
const copyTextToClipboardFallback = async () => {
|
||||
try {
|
||||
const text = await getTextPromise;
|
||||
if (text) {
|
||||
copyTextToClipboard(text);
|
||||
} else {
|
||||
onFailure();
|
||||
}
|
||||
return Boolean(text);
|
||||
} catch {
|
||||
onFailure();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if (!CLIPBOARD_ITEM_SUPPORTED || !navigator.clipboard.write) {
|
||||
if (await copyTextToClipboardFallback()) onSuccess();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let hasGetDataError = false;
|
||||
const rejectGetDataError = () => Promise.reject(new Error('GET_DATA_ERROR'));
|
||||
|
||||
const clipboardTextItem = new ClipboardItem({
|
||||
'text/plain': getTextPromise.then((text) => text || rejectGetDataError()).catch(() => {
|
||||
hasGetDataError = true;
|
||||
return '';
|
||||
}),
|
||||
});
|
||||
await navigator.clipboard.write([clipboardTextItem]);
|
||||
if (hasGetDataError) {
|
||||
onFailure();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Promises in ClipboardItem aren't supported in older Chrome versions
|
||||
if (!await copyTextToClipboardFallback()) return;
|
||||
}
|
||||
onSuccess();
|
||||
};
|
||||
|
||||
async function copyBlobToClipboard(pngBlob: Blob | null) {
|
||||
if (!pngBlob || !CLIPBOARD_ITEM_SUPPORTED) {
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user