diff --git a/src/message/__tests__/messageActionSheet-test.js b/src/message/__tests__/messageActionSheet-test.js index 37917a0c43d..f09da9d5b13 100644 --- a/src/message/__tests__/messageActionSheet-test.js +++ b/src/message/__tests__/messageActionSheet-test.js @@ -48,6 +48,35 @@ describe('constructActionButtons', () => { expect(buttons).toContain('unstarMessage'); }); + + test('show copy link option if long pressed on link', () => { + const message = deepFreeze({ + id: 1, + }); + + const buttons = constructMessageActionButtons({ + backgroundData: { auth, flags }, + message, + narrow, + href: 'https://zulipchat.com', + }); + + expect(buttons).toContain('copyLinkToClipboard'); + }); + + test('show copy message option if long pressed on a text', () => { + const message = deepFreeze({ + id: 1, + }); + + const buttons = constructMessageActionButtons({ + backgroundData: { auth, flags }, + message, + narrow, + }); + + expect(buttons).toContain('copyToClipboard'); + }); }); describe('constructHeaderActionButtons', () => { diff --git a/src/message/messageActionSheet.js b/src/message/messageActionSheet.js index 94b362493f9..0497fd6ecf3 100644 --- a/src/message/messageActionSheet.js +++ b/src/message/messageActionSheet.js @@ -17,6 +17,7 @@ type ButtonDescription = { message: Message, subscriptions: Subscription[], dispatch: Dispatch, + href: string, _: GetText, }): void | Promise, title: string, @@ -42,6 +43,12 @@ const copyToClipboard = async ({ _, auth, message }) => { }; copyToClipboard.title = 'Copy to clipboard'; +const copyLinkToClipboard = async ({ _, href }) => { + Clipboard.setString(href); + showToast(_('Link copied')); +}; +copyLinkToClipboard.title = 'Copy link to clipboard'; + const editMessage = async ({ message, dispatch }) => { dispatch(startEditMessage(message.id, message.subject)); }; @@ -112,6 +119,7 @@ const allButtonsRaw = { addReaction, reply, copyToClipboard, + copyLinkToClipboard, shareMessage, editMessage, deleteMessage, @@ -140,6 +148,7 @@ type ConstructSheetParams = {| backgroundData: BackgroundData, message: Message, narrow: Narrow, + href: string, |}; export const constructHeaderActionButtons = ({ @@ -170,6 +179,7 @@ export const constructMessageActionButtons = ({ backgroundData: { auth, flags }, message, narrow, + href, }: ConstructSheetParams): ButtonCode[] => { const buttons = []; if (!isAnOutboxMessage(message) && messageNotDeleted(message)) { @@ -179,7 +189,11 @@ export const constructMessageActionButtons = ({ buttons.push('reply'); } if (messageNotDeleted(message)) { - buttons.push('copyToClipboard'); + if (href) { + buttons.push('copyLinkToClipboard'); + } else { + buttons.push('copyToClipboard'); + } buttons.push('shareMessage'); } if ( diff --git a/src/webview/js/generatedEs3.js b/src/webview/js/generatedEs3.js index 8e067d8adbb..e220a783947 100644 --- a/src/webview/js/generatedEs3.js +++ b/src/webview/js/generatedEs3.js @@ -484,7 +484,8 @@ var handleLongPress = function handleLongPress(target) { sendMessage({ type: 'longPress', target: target.matches('.header') ? 'header' : 'message', - messageId: getMessageIdFromNode(target) + messageId: getMessageIdFromNode(target), + href: target.matches('a') ? target.getAttribute('href') : '' }); }; diff --git a/src/webview/js/js.js b/src/webview/js/js.js index 32d05a243a5..d4ae0b4855d 100644 --- a/src/webview/js/js.js +++ b/src/webview/js/js.js @@ -646,6 +646,7 @@ const handleLongPress = (target: Element) => { type: 'longPress', target: target.matches('.header') ? 'header' : 'message', messageId: getMessageIdFromNode(target), + href: target.matches('a') ? target.getAttribute('href') : '', }); }; diff --git a/src/webview/webViewEventHandlers.js b/src/webview/webViewEventHandlers.js index 0966b52081e..08e908c140a 100644 --- a/src/webview/webViewEventHandlers.js +++ b/src/webview/webViewEventHandlers.js @@ -79,6 +79,7 @@ type MessageListEventLongPress = {| type: 'longPress', target: 'message' | 'header', messageId: number, + href: string, |}; type MessageListEventDebug = {| @@ -150,7 +151,13 @@ const handleImage = (props: Props, src: string, messageId: number) => { } }; -const handleLongPress = (props: Props, _: GetText, isHeader: boolean, messageId: number) => { +const handleLongPress = ( + props: Props, + _: GetText, + isHeader: boolean, + messageId: number, + href: string, +) => { const message = props.messages.find(x => x.id === messageId); if (!message) { return; @@ -160,6 +167,7 @@ const handleLongPress = (props: Props, _: GetText, isHeader: boolean, messageId: backgroundData, message, narrow, + href, }); }; @@ -187,7 +195,7 @@ export const handleMessageListEvent = (props: Props, _: GetText, event: MessageL break; case 'longPress': - handleLongPress(props, _, event.target === 'header', event.messageId); + handleLongPress(props, _, event.target === 'header', event.messageId, event.href); break; case 'url': diff --git a/static/translations/messages_en.json b/static/translations/messages_en.json index 919e381bea2..fbc12b687b3 100644 --- a/static/translations/messages_en.json +++ b/static/translations/messages_en.json @@ -50,6 +50,7 @@ "Reply": "Reply", "Add a reaction": "Add a reaction", "Copy to clipboard": "Copy to clipboard", + "Copy link to clipboard": "Copy link to clipboard", "Mute topic": "Mute topic", "Unmute topic": "Unmute topic", "Mute stream": "Mute stream", @@ -118,6 +119,7 @@ "Unstar message": "Unstar message", "Cancel": "Cancel", "Message copied": "Message copied", + "Link copied": "Link copied", "Edit message": "Edit message", "Network request failed": "Network request failed", "show": "show",