mirror of https://github.com/vector-im/riot-web
Cleanup `MessageContextMenu` code (#8351)
parent
2f3249793f
commit
511965b840
|
@ -21,7 +21,6 @@ import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
|||
import { EventType, RelationType } from "matrix-js-sdk/src/@types/event";
|
||||
import { Relations } from 'matrix-js-sdk/src/models/relations';
|
||||
import { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
|
||||
import { M_LOCATION } from 'matrix-js-sdk/src/@types/location';
|
||||
import { M_POLL_START } from "matrix-events-sdk";
|
||||
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
|
@ -31,7 +30,7 @@ import Modal from '../../../Modal';
|
|||
import Resend from '../../../Resend';
|
||||
import SettingsStore from '../../../settings/SettingsStore';
|
||||
import { isUrlPermitted } from '../../../HtmlUtils';
|
||||
import { canEditContent, editEvent, isContentActionable } from '../../../utils/EventUtils';
|
||||
import { canEditContent, canForward, editEvent, isContentActionable, isLocationEvent } from '../../../utils/EventUtils';
|
||||
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from './IconizedContextMenu';
|
||||
import { ReadPinsEventId } from "../right_panel/types";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
|
@ -49,20 +48,11 @@ import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInse
|
|||
import EndPollDialog from '../dialogs/EndPollDialog';
|
||||
import { isPollEnded } from '../messages/MPollBody';
|
||||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { GetRelationsForEvent } from "../rooms/EventTile";
|
||||
import { GetRelationsForEvent, IEventTileOps } from "../rooms/EventTile";
|
||||
import { OpenForwardDialogPayload } from "../../../dispatcher/payloads/OpenForwardDialogPayload";
|
||||
import { OpenReportEventDialogPayload } from "../../../dispatcher/payloads/OpenReportEventDialogPayload";
|
||||
import { createMapSiteLink } from '../../../utils/location';
|
||||
|
||||
export interface IEventTileOps {
|
||||
isWidgetHidden(): boolean;
|
||||
unhideWidget(): void;
|
||||
}
|
||||
|
||||
export interface IOperableEventTile {
|
||||
getEventTileOps(): IEventTileOps;
|
||||
}
|
||||
|
||||
interface IProps extends IPosition {
|
||||
chevronFace: ChevronFace;
|
||||
/* the MatrixEvent associated with the context menu */
|
||||
|
@ -343,28 +333,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
const isThreadRootEvent = isThread && mxEvent?.getThread()?.rootEvent === mxEvent;
|
||||
|
||||
let openInMapSiteButton: JSX.Element;
|
||||
let endPollButton: JSX.Element;
|
||||
let resendReactionsButton: JSX.Element;
|
||||
let redactButton: JSX.Element;
|
||||
let forwardButton: JSX.Element;
|
||||
let pinButton: JSX.Element;
|
||||
let unhidePreviewButton: JSX.Element;
|
||||
let externalURLButton: JSX.Element;
|
||||
let quoteButton: JSX.Element;
|
||||
let redactItemList: JSX.Element;
|
||||
let reportEventButton: JSX.Element;
|
||||
let copyButton: JSX.Element;
|
||||
let editButton: JSX.Element;
|
||||
let replyButton: JSX.Element;
|
||||
let reactButton: JSX.Element;
|
||||
let reactionPicker: JSX.Element;
|
||||
let quickItemsList: JSX.Element;
|
||||
let nativeItemsList: JSX.Element;
|
||||
let permalinkButton: JSX.Element;
|
||||
let collapseReplyChainButton: JSX.Element;
|
||||
let viewInRoomButton: JSX.Element;
|
||||
|
||||
if (!mxEvent.isRedacted() && unsentReactionsCount !== 0) {
|
||||
resendReactionsButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -375,6 +344,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let redactButton: JSX.Element;
|
||||
if (isSent && this.state.canRedact) {
|
||||
redactButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -385,6 +355,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let openInMapSiteButton: JSX.Element;
|
||||
if (this.canOpenInMapSite(mxEvent)) {
|
||||
const mapSiteLink = createMapSiteLink(mxEvent);
|
||||
openInMapSiteButton = (
|
||||
|
@ -404,6 +375,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let forwardButton: JSX.Element;
|
||||
if (contentActionable && canForward(mxEvent)) {
|
||||
forwardButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -414,6 +386,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let pinButton: JSX.Element;
|
||||
if (contentActionable && this.state.canPin) {
|
||||
pinButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -435,6 +408,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let unhidePreviewButton: JSX.Element;
|
||||
if (eventTileOps?.isWidgetHidden()) {
|
||||
unhidePreviewButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -445,6 +419,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let permalinkButton: JSX.Element;
|
||||
if (permalink) {
|
||||
permalinkButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -468,6 +443,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let endPollButton: JSX.Element;
|
||||
if (this.canEndPoll(mxEvent)) {
|
||||
endPollButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -478,6 +454,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let quoteButton: JSX.Element;
|
||||
if (eventTileOps) { // this event is rendered using TextualBody
|
||||
quoteButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -489,6 +466,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
// Bridges can provide a 'external_url' to link back to the source.
|
||||
let externalURLButton: JSX.Element;
|
||||
if (
|
||||
typeof (mxEvent.getContent().external_url) === "string" &&
|
||||
isUrlPermitted(mxEvent.getContent().external_url)
|
||||
|
@ -511,6 +489,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let collapseReplyChainButton: JSX.Element;
|
||||
if (collapseReplyChain) {
|
||||
collapseReplyChainButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -521,6 +500,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let reportEventButton: JSX.Element;
|
||||
if (mxEvent.getSender() !== me) {
|
||||
reportEventButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -531,6 +511,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let copyButton: JSX.Element;
|
||||
if (rightClick && getSelectedText()) {
|
||||
copyButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -542,6 +523,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let editButton: JSX.Element;
|
||||
if (rightClick && canEditContent(mxEvent)) {
|
||||
editButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -552,6 +534,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let replyButton: JSX.Element;
|
||||
if (rightClick && contentActionable && canSendMessages) {
|
||||
replyButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -562,6 +545,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let reactButton;
|
||||
if (rightClick && contentActionable && canReact) {
|
||||
reactButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -573,6 +557,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let viewInRoomButton: JSX.Element;
|
||||
if (isThreadRootEvent) {
|
||||
viewInRoomButton = (
|
||||
<IconizedContextMenuOption
|
||||
|
@ -583,6 +568,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let nativeItemsList: JSX.Element;
|
||||
if (copyButton) {
|
||||
nativeItemsList = (
|
||||
<IconizedContextMenuOptionList>
|
||||
|
@ -591,6 +577,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let quickItemsList: JSX.Element;
|
||||
if (editButton || replyButton || reactButton) {
|
||||
quickItemsList = (
|
||||
<IconizedContextMenuOptionList>
|
||||
|
@ -619,6 +606,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
</IconizedContextMenuOptionList>
|
||||
);
|
||||
|
||||
let redactItemList: JSX.Element;
|
||||
if (redactButton) {
|
||||
redactItemList = (
|
||||
<IconizedContextMenuOptionList red>
|
||||
|
@ -627,6 +615,7 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
let reactionPicker: JSX.Element;
|
||||
if (this.state.reactionPickerDisplayed) {
|
||||
const buttonRect = (this.reactButtonRef.current as HTMLElement)?.getBoundingClientRect();
|
||||
reactionPicker = (
|
||||
|
@ -662,20 +651,3 @@ export default class MessageContextMenu extends React.Component<IProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
function canForward(event: MatrixEvent): boolean {
|
||||
return !(
|
||||
isLocationEvent(event) ||
|
||||
M_POLL_START.matches(event.getType())
|
||||
);
|
||||
}
|
||||
|
||||
function isLocationEvent(event: MatrixEvent): boolean {
|
||||
const eventType = event.getType();
|
||||
return (
|
||||
M_LOCATION.matches(eventType) ||
|
||||
(
|
||||
eventType === EventType.RoomMessage &&
|
||||
M_LOCATION.matches(event.getContent().msgtype)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import { Mjolnir } from "../../../mjolnir/Mjolnir";
|
|||
import RedactedBody from "./RedactedBody";
|
||||
import UnknownBody from "./UnknownBody";
|
||||
import { IMediaBody } from "./IMediaBody";
|
||||
import { IOperableEventTile } from "../context_menus/MessageContextMenu";
|
||||
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
|
||||
import { ReactAnyComponent } from "../../../@types/common";
|
||||
import { IBodyProps } from "./IBodyProps";
|
||||
|
@ -41,6 +40,7 @@ import MPollBody from "./MPollBody";
|
|||
import MLocationBody from "./MLocationBody";
|
||||
import MjolnirBody from "./MjolnirBody";
|
||||
import MBeaconBody from "./MBeaconBody";
|
||||
import { IEventTileOps } from "../rooms/EventTile";
|
||||
|
||||
// onMessageAllowed is handled internally
|
||||
interface IProps extends Omit<IBodyProps, "onMessageAllowed" | "mediaEventHelper"> {
|
||||
|
@ -54,6 +54,10 @@ interface IProps extends Omit<IBodyProps, "onMessageAllowed" | "mediaEventHelper
|
|||
isSeeingThroughMessageHiddenForModeration?: boolean;
|
||||
}
|
||||
|
||||
export interface IOperableEventTile {
|
||||
getEventTileOps(): IEventTileOps;
|
||||
}
|
||||
|
||||
export default class MessageEvent extends React.Component<IProps> implements IMediaBody, IOperableEventTile {
|
||||
private body: React.RefObject<React.Component | IOperableEventTile> = createRef();
|
||||
private mediaHelper: MediaEventHelper;
|
||||
|
|
|
@ -38,7 +38,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
|||
import { E2EState } from "./E2EIcon";
|
||||
import { toRem } from "../../../utils/units";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import MessageContextMenu, { IEventTileOps } from "../context_menus/MessageContextMenu";
|
||||
import MessageContextMenu from "../context_menus/MessageContextMenu";
|
||||
import { aboveRightOf } from '../../structures/ContextMenu';
|
||||
import { objectHasDiff } from "../../../utils/objects";
|
||||
import Tooltip from "../elements/Tooltip";
|
||||
|
@ -99,6 +99,11 @@ export interface IReadReceiptProps {
|
|||
ts: number;
|
||||
}
|
||||
|
||||
export interface IEventTileOps {
|
||||
isWidgetHidden(): boolean;
|
||||
unhideWidget(): void;
|
||||
}
|
||||
|
||||
export interface IEventTileType extends React.Component {
|
||||
getEventTileOps?(): IEventTileOps;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import { EventType, EVENT_VISIBILITY_CHANGE_TYPE, MsgType, RelationType } from "
|
|||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import { logger } from 'matrix-js-sdk/src/logger';
|
||||
import { M_POLL_START } from "matrix-events-sdk";
|
||||
import { M_LOCATION } from "matrix-js-sdk/src/@types/location";
|
||||
|
||||
import { MatrixClientPeg } from '../MatrixClientPeg';
|
||||
import shouldHideEvent from "../shouldHideEvent";
|
||||
|
@ -262,3 +263,21 @@ export function editEvent(
|
|||
export function canCancel(status: EventStatus): boolean {
|
||||
return status === EventStatus.QUEUED || status === EventStatus.NOT_SENT || status === EventStatus.ENCRYPTING;
|
||||
}
|
||||
|
||||
export const isLocationEvent = (event: MatrixEvent): boolean => {
|
||||
const eventType = event.getType();
|
||||
return (
|
||||
M_LOCATION.matches(eventType) ||
|
||||
(
|
||||
eventType === EventType.RoomMessage &&
|
||||
M_LOCATION.matches(event.getContent().msgtype)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export function canForward(event: MatrixEvent): boolean {
|
||||
return !(
|
||||
isLocationEvent(event) ||
|
||||
M_POLL_START.matches(event.getType())
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue