Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit b1daf3f

Browse files
Add a Copy link button to the right-click message context-menu labs feature (#8527)
* Simplify `Share` button Signed-off-by: Šimon Brandner <[email protected]> * Add proper `Copy link` button Signed-off-by: Šimon Brandner <[email protected]> * i18n Signed-off-by: Šimon Brandner <[email protected]>
1 parent dfc7224 commit b1daf3f

File tree

3 files changed

+48
-35
lines changed

3 files changed

+48
-35
lines changed

src/components/views/context_menus/MessageContextMenu.tsx

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ interface IProps extends IPosition {
7070
rightClick?: boolean;
7171
// The Relations model from the JS SDK for reactions to `mxEvent`
7272
reactions?: Relations;
73-
// A permalink to the event
74-
showPermalink?: boolean;
73+
// A permalink to this event or an href of an anchor element the user has clicked
74+
link?: string;
7575

7676
getRelationsForEvent?: GetRelationsForEvent;
7777
}
@@ -227,7 +227,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
227227
this.closeMenu();
228228
};
229229

230-
private onPermalinkClick = (e: React.MouseEvent): void => {
230+
private onShareClick = (e: React.MouseEvent): void => {
231231
e.preventDefault();
232232
Modal.createTrackedDialog('share room message dialog', '', ShareDialog, {
233233
target: this.props.mxEvent,
@@ -236,9 +236,9 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
236236
this.closeMenu();
237237
};
238238

239-
private onCopyPermalinkClick = (e: ButtonEvent): void => {
239+
private onCopyLinkClick = (e: ButtonEvent): void => {
240240
e.preventDefault(); // So that we don't open the permalink
241-
copyPlaintext(this.getPermalink());
241+
copyPlaintext(this.props.link);
242242
this.closeMenu();
243243
};
244244

@@ -295,11 +295,6 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
295295
});
296296
}
297297

298-
private getPermalink(): string {
299-
if (!this.props.permalinkCreator) return;
300-
return this.props.permalinkCreator.forEvent(this.props.mxEvent.getId());
301-
}
302-
303298
private getUnsentReactions(): MatrixEvent[] {
304299
return this.getReactions(e => e.status === EventStatus.NOT_SENT);
305300
}
@@ -318,11 +313,11 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
318313
public render(): JSX.Element {
319314
const cli = MatrixClientPeg.get();
320315
const me = cli.getUserId();
321-
const { mxEvent, rightClick, showPermalink, eventTileOps, reactions, collapseReplyChain } = this.props;
316+
const { mxEvent, rightClick, link, eventTileOps, reactions, collapseReplyChain } = this.props;
322317
const eventStatus = mxEvent.status;
323318
const unsentReactionsCount = this.getUnsentReactions().length;
324319
const contentActionable = isContentActionable(mxEvent);
325-
const permalink = this.getPermalink();
320+
const permalink = this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId());
326321
// status is SENT before remote-echo, null after
327322
const isSent = !eventStatus || eventStatus === EventStatus.SENT;
328323
const { timelineRenderingType, canReact, canSendMessages } = this.context;
@@ -420,17 +415,13 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
420415
if (permalink) {
421416
permalinkButton = (
422417
<IconizedContextMenuOption
423-
iconClassName={showPermalink
424-
? "mx_MessageContextMenu_iconCopy"
425-
: "mx_MessageContextMenu_iconPermalink"
426-
}
427-
onClick={showPermalink ? this.onCopyPermalinkClick : this.onPermalinkClick}
428-
label={showPermalink ? _t('Copy link') : _t('Share')}
418+
iconClassName="mx_MessageContextMenu_iconPermalink"
419+
onClick={this.onShareClick}
420+
label={_t('Share')}
429421
element="a"
430422
{
431423
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
432424
...{
433-
434425
href: permalink,
435426
target: "_blank",
436427
rel: "noreferrer noopener",
@@ -508,6 +499,26 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
508499
);
509500
}
510501

502+
let copyLinkButton: JSX.Element;
503+
if (link) {
504+
copyLinkButton = (
505+
<IconizedContextMenuOption
506+
iconClassName="mx_MessageContextMenu_iconCopy"
507+
onClick={this.onCopyLinkClick}
508+
label={_t('Copy link')}
509+
element="a"
510+
{
511+
// XXX: Typescript signature for AccessibleButton doesn't work properly for non-inputs like `a`
512+
...{
513+
href: link,
514+
target: "_blank",
515+
rel: "noreferrer noopener",
516+
}
517+
}
518+
/>
519+
);
520+
}
521+
511522
let copyButton: JSX.Element;
512523
if (rightClick && getSelectedText()) {
513524
copyButton = (
@@ -566,10 +577,11 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
566577
}
567578

568579
let nativeItemsList: JSX.Element;
569-
if (copyButton) {
580+
if (copyButton || copyLinkButton) {
570581
nativeItemsList = (
571582
<IconizedContextMenuOptionList>
572583
{ copyButton }
584+
{ copyLinkButton }
573585
</IconizedContextMenuOptionList>
574586
);
575587
}

src/components/views/rooms/EventTile.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ interface IState {
234234
// Position of the context menu
235235
contextMenu?: {
236236
position: Pick<DOMRect, "top" | "left" | "bottom">;
237-
showPermalink?: boolean;
237+
link?: string;
238238
};
239239

240240
isQuoteExpanded?: boolean;
@@ -842,26 +842,27 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
842842
};
843843

844844
private onTimestampContextMenu = (ev: React.MouseEvent): void => {
845-
this.showContextMenu(ev, true);
845+
this.showContextMenu(ev, this.props.permalinkCreator?.forEvent(this.props.mxEvent.getId()));
846846
};
847847

848-
private showContextMenu(ev: React.MouseEvent, showPermalink?: boolean): void {
848+
private showContextMenu(ev: React.MouseEvent, permalink?: string): void {
849+
const clickTarget = ev.target as HTMLElement;
850+
849851
// Return if message right-click context menu isn't enabled
850852
if (!SettingsStore.getValue("feature_message_right_click_context_menu")) return;
851853

852-
// Return if we're in a browser and click either an a tag or we have
853-
// selected text, as in those cases we want to use the native browser
854-
// menu
855-
const clickTarget = ev.target as HTMLElement;
856-
if (
857-
!PlatformPeg.get().allowOverridingNativeContextMenus() &&
858-
(clickTarget.tagName === "a" || clickTarget.closest("a") || getSelectedText())
859-
) return;
854+
// Try to find an anchor element
855+
const anchorElement = (clickTarget instanceof HTMLAnchorElement) ? clickTarget : clickTarget.closest("a");
860856

861857
// There is no way to copy non-PNG images into clipboard, so we can't
862858
// have our own handling for copying images, so we leave it to the
863859
// Electron layer (webcontents-handler.ts)
864-
if (ev.target instanceof HTMLImageElement) return;
860+
if (clickTarget instanceof HTMLImageElement) return;
861+
862+
// Return if we're in a browser and click either an a tag or we have
863+
// selected text, as in those cases we want to use the native browser
864+
// menu
865+
if (!PlatformPeg.get().allowOverridingNativeContextMenus() && (getSelectedText() || anchorElement)) return;
865866

866867
// We don't want to show the menu when editing a message
867868
if (this.props.editState) return;
@@ -875,7 +876,7 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
875876
top: ev.clientY,
876877
bottom: ev.clientY,
877878
},
878-
showPermalink: showPermalink,
879+
link: anchorElement?.href || permalink,
879880
},
880881
actionBarFocused: true,
881882
});
@@ -924,7 +925,7 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
924925
onFinished={this.onCloseMenu}
925926
rightClick={true}
926927
reactions={this.state.reactions}
927-
showPermalink={this.state.contextMenu.showPermalink}
928+
link={this.state.contextMenu.link}
928929
/>
929930
);
930931
}

src/i18n/strings/en_EN.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2921,10 +2921,10 @@
29212921
"Forward": "Forward",
29222922
"View source": "View source",
29232923
"Show preview": "Show preview",
2924-
"Copy link": "Copy link",
29252924
"Source URL": "Source URL",
29262925
"Collapse reply thread": "Collapse reply thread",
29272926
"Report": "Report",
2927+
"Copy link": "Copy link",
29282928
"Forget": "Forget",
29292929
"Mentions only": "Mentions only",
29302930
"See room timeline (devtools)": "See room timeline (devtools)",

0 commit comments

Comments
 (0)