Convert several internal maps to real maps

pull/28788/head^2
Travis Ralston 2022-08-29 17:02:24 -06:00
parent aace3a8c28
commit 37a527c61f
2 changed files with 71 additions and 63 deletions

View File

@ -59,11 +59,30 @@ export interface IOperableEventTile {
getEventTileOps(): IEventTileOps; getEventTileOps(): IEventTileOps;
} }
const baseBodyTypes = new Map<string, typeof React.Component>([
[MsgType.Text, TextualBody],
[MsgType.Notice, TextualBody],
[MsgType.Emote, TextualBody],
[MsgType.Image, MImageBody],
[MsgType.File, MFileBody],
[MsgType.Audio, MVoiceOrAudioBody],
[MsgType.Video, MVideoBody],
]);
const baseEvTypes = new Map<string, React.ComponentType<Partial<IBodyProps>>>([
[EventType.Sticker, MStickerBody],
[M_POLL_START.name, MPollBody],
[M_POLL_START.altName, MPollBody],
[M_BEACON_INFO.name, MBeaconBody],
[M_BEACON_INFO.altName, MBeaconBody],
]);
export default class MessageEvent extends React.Component<IProps> implements IMediaBody, IOperableEventTile { export default class MessageEvent extends React.Component<IProps> implements IMediaBody, IOperableEventTile {
private body: React.RefObject<React.Component | IOperableEventTile> = createRef(); private body: React.RefObject<React.Component | IOperableEventTile> = createRef();
private mediaHelper: MediaEventHelper; private mediaHelper: MediaEventHelper;
private bodyTypes = new Map<string, typeof React.Component>(baseBodyTypes.entries());
private evTypes = new Map<string, React.ComponentType<Partial<IBodyProps>>>(baseEvTypes.entries());
static contextType = MatrixClientContext; public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>; public context!: React.ContextType<typeof MatrixClientContext>;
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) { public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
@ -72,6 +91,8 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
if (MediaEventHelper.isEligible(this.props.mxEvent)) { if (MediaEventHelper.isEligible(this.props.mxEvent)) {
this.mediaHelper = new MediaEventHelper(this.props.mxEvent); this.mediaHelper = new MediaEventHelper(this.props.mxEvent);
} }
this.updateComponentMaps();
} }
public componentDidMount(): void { public componentDidMount(): void {
@ -88,32 +109,20 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
this.mediaHelper?.destroy(); this.mediaHelper?.destroy();
this.mediaHelper = new MediaEventHelper(this.props.mxEvent); this.mediaHelper = new MediaEventHelper(this.props.mxEvent);
} }
this.updateComponentMaps();
} }
private get bodyTypes(): Record<string, typeof React.Component> { private updateComponentMaps() {
return { this.bodyTypes = new Map<string, typeof React.Component>(baseBodyTypes.entries());
[MsgType.Text]: TextualBody, for (const [bodyType, bodyComponent] of Object.entries(this.props.overrideBodyTypes ?? {})) {
[MsgType.Notice]: TextualBody, this.bodyTypes.set(bodyType, bodyComponent);
[MsgType.Emote]: TextualBody, }
[MsgType.Image]: MImageBody,
[MsgType.File]: MFileBody,
[MsgType.Audio]: MVoiceOrAudioBody,
[MsgType.Video]: MVideoBody,
...(this.props.overrideBodyTypes || {}), this.evTypes = new Map<string, React.ComponentType<Partial<IBodyProps>>>(baseEvTypes.entries());
}; for (const [evType, evComponent] of Object.entries(this.props.overrideEventTypes ?? {})) {
} this.evTypes.set(evType, evComponent);
}
private get evTypes(): Record<string, React.ComponentType<Partial<IBodyProps>>> {
return {
[EventType.Sticker]: MStickerBody,
[M_POLL_START.name]: MPollBody,
[M_POLL_START.altName]: MPollBody,
[M_BEACON_INFO.name]: MBeaconBody,
[M_BEACON_INFO.altName]: MBeaconBody,
...(this.props.overrideEventTypes || {}),
};
} }
public getEventTileOps = () => { public getEventTileOps = () => {
@ -143,13 +152,13 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
let BodyType: React.ComponentType<Partial<IBodyProps>> | ReactAnyComponent = RedactedBody; let BodyType: React.ComponentType<Partial<IBodyProps>> | ReactAnyComponent = RedactedBody;
if (!this.props.mxEvent.isRedacted()) { if (!this.props.mxEvent.isRedacted()) {
// only resolve BodyType if event is not redacted // only resolve BodyType if event is not redacted
if (type && this.evTypes[type]) { if (type && this.evTypes.has(type)) {
BodyType = this.evTypes[type]; BodyType = this.evTypes.get(type);
} else if (msgtype && this.bodyTypes[msgtype]) { } else if (msgtype && this.bodyTypes.has(msgtype)) {
BodyType = this.bodyTypes[msgtype]; BodyType = this.bodyTypes.get(msgtype);
} else if (content.url) { } else if (content.url) {
// Fallback to MFileBody if there's a content URL // Fallback to MFileBody if there's a content URL
BodyType = this.bodyTypes[MsgType.File]; BodyType = this.bodyTypes.get(MsgType.File);
} else { } else {
// Fallback to UnknownBody otherwise if not redacted // Fallback to UnknownBody otherwise if not redacted
BodyType = UnknownBody; BodyType = UnknownBody;

View File

@ -67,7 +67,6 @@ export interface EventTileTypeProps {
type FactoryProps = Omit<EventTileTypeProps, "ref">; type FactoryProps = Omit<EventTileTypeProps, "ref">;
type Factory<X = FactoryProps> = (ref: Optional<React.RefObject<any>>, props: X) => JSX.Element; type Factory<X = FactoryProps> = (ref: Optional<React.RefObject<any>>, props: X) => JSX.Element;
type FactoryMap = Record<string, Factory>;
const MessageEventFactory: Factory = (ref, props) => <MessageEvent ref={ref} {...props} />; const MessageEventFactory: Factory = (ref, props) => <MessageEvent ref={ref} {...props} />;
const KeyVerificationConclFactory: Factory = (ref, props) => <MKeyVerificationConclusion ref={ref} {...props} />; const KeyVerificationConclFactory: Factory = (ref, props) => <MKeyVerificationConclusion ref={ref} {...props} />;
@ -82,40 +81,40 @@ const HiddenEventFactory: Factory = (ref, props) => <HiddenBody ref={ref} {...pr
export const JitsiEventFactory: Factory = (ref, props) => <MJitsiWidgetEvent ref={ref} {...props} />; export const JitsiEventFactory: Factory = (ref, props) => <MJitsiWidgetEvent ref={ref} {...props} />;
export const JSONEventFactory: Factory = (ref, props) => <ViewSourceEvent ref={ref} {...props} />; export const JSONEventFactory: Factory = (ref, props) => <ViewSourceEvent ref={ref} {...props} />;
const EVENT_TILE_TYPES: FactoryMap = { const EVENT_TILE_TYPES = new Map<string, Factory>([
[EventType.RoomMessage]: MessageEventFactory, // note that verification requests are handled in pickFactory() [EventType.RoomMessage, MessageEventFactory], // note that verification requests are handled in pickFactory()
[EventType.Sticker]: MessageEventFactory, [EventType.Sticker, MessageEventFactory],
[M_POLL_START.name]: MessageEventFactory, [M_POLL_START.name, MessageEventFactory],
[M_POLL_START.altName]: MessageEventFactory, [M_POLL_START.altName, MessageEventFactory],
[EventType.KeyVerificationCancel]: KeyVerificationConclFactory, [EventType.KeyVerificationCancel, KeyVerificationConclFactory],
[EventType.KeyVerificationDone]: KeyVerificationConclFactory, [EventType.KeyVerificationDone, KeyVerificationConclFactory],
[EventType.CallInvite]: CallEventFactory, // note that this requires a special factory type [EventType.CallInvite, CallEventFactory], // note that this requires a special factory type
}; ]);
const STATE_EVENT_TILE_TYPES: FactoryMap = { const STATE_EVENT_TILE_TYPES = new Map<string, Factory>([
[EventType.RoomEncryption]: (ref, props) => <EncryptionEvent ref={ref} {...props} />, [EventType.RoomEncryption, (ref, props) => <EncryptionEvent ref={ref} {...props} />],
[EventType.RoomCanonicalAlias]: TextualEventFactory, [EventType.RoomCanonicalAlias, TextualEventFactory],
[EventType.RoomCreate]: (ref, props) => <RoomCreate ref={ref} {...props} />, [EventType.RoomCreate, (ref, props) => <RoomCreate ref={ref} {...props} />],
[EventType.RoomMember]: TextualEventFactory, [EventType.RoomMember, TextualEventFactory],
[EventType.RoomName]: TextualEventFactory, [EventType.RoomName, TextualEventFactory],
[EventType.RoomAvatar]: (ref, props) => <RoomAvatarEvent ref={ref} {...props} />, [EventType.RoomAvatar, (ref, props) => <RoomAvatarEvent ref={ref} {...props} />],
[EventType.RoomThirdPartyInvite]: TextualEventFactory, [EventType.RoomThirdPartyInvite, TextualEventFactory],
[EventType.RoomHistoryVisibility]: TextualEventFactory, [EventType.RoomHistoryVisibility, TextualEventFactory],
[EventType.RoomTopic]: TextualEventFactory, [EventType.RoomTopic, TextualEventFactory],
[EventType.RoomPowerLevels]: TextualEventFactory, [EventType.RoomPowerLevels, TextualEventFactory],
[EventType.RoomPinnedEvents]: TextualEventFactory, [EventType.RoomPinnedEvents, TextualEventFactory],
[EventType.RoomServerAcl]: TextualEventFactory, [EventType.RoomServerAcl, TextualEventFactory],
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
'im.vector.modular.widgets': TextualEventFactory, // note that Jitsi widgets are special in pickFactory() ['im.vector.modular.widgets', TextualEventFactory], // note that Jitsi widgets are special in pickFactory()
[WIDGET_LAYOUT_EVENT_TYPE]: TextualEventFactory, [WIDGET_LAYOUT_EVENT_TYPE, TextualEventFactory],
[EventType.RoomTombstone]: TextualEventFactory, [EventType.RoomTombstone, TextualEventFactory],
[EventType.RoomJoinRules]: TextualEventFactory, [EventType.RoomJoinRules, TextualEventFactory],
[EventType.RoomGuestAccess]: TextualEventFactory, [EventType.RoomGuestAccess, TextualEventFactory],
}; ]);
// Add all the Mjolnir stuff to the renderer too // Add all the Mjolnir stuff to the renderer too
for (const evType of ALL_RULE_TYPES) { for (const evType of ALL_RULE_TYPES) {
STATE_EVENT_TILE_TYPES[evType] = TextualEventFactory; STATE_EVENT_TILE_TYPES.set(evType, TextualEventFactory);
} }
// These events should be recorded in the STATE_EVENT_TILE_TYPES // These events should be recorded in the STATE_EVENT_TILE_TYPES
@ -225,11 +224,11 @@ export function pickFactory(
return noEventFactoryFactory(); // improper event type to render return noEventFactoryFactory(); // improper event type to render
} }
if (STATE_EVENT_TILE_TYPES[evType] === TextualEventFactory && !hasText(mxEvent, showHiddenEvents)) { if (STATE_EVENT_TILE_TYPES.get(evType) === TextualEventFactory && !hasText(mxEvent, showHiddenEvents)) {
return noEventFactoryFactory(); return noEventFactoryFactory();
} }
return STATE_EVENT_TILE_TYPES[evType] ?? noEventFactoryFactory(); return STATE_EVENT_TILE_TYPES.get(evType) ?? noEventFactoryFactory();
} }
// Blanket override for all events. The MessageEvent component handles redacted states for us. // Blanket override for all events. The MessageEvent component handles redacted states for us.
@ -241,7 +240,7 @@ export function pickFactory(
return noEventFactoryFactory(); return noEventFactoryFactory();
} }
return EVENT_TILE_TYPES[evType] ?? noEventFactoryFactory(); return EVENT_TILE_TYPES.get(evType) ?? noEventFactoryFactory();
} }
/** /**
@ -391,7 +390,7 @@ export function haveRendererForEvent(mxEvent: MatrixEvent, showHiddenEvents: boo
if (!handler) return false; if (!handler) return false;
if (handler === TextualEventFactory) { if (handler === TextualEventFactory) {
return hasText(mxEvent, showHiddenEvents); return hasText(mxEvent, showHiddenEvents);
} else if (handler === STATE_EVENT_TILE_TYPES[EventType.RoomCreate]) { } else if (handler === STATE_EVENT_TILE_TYPES.get(EventType.RoomCreate)) {
return Boolean(mxEvent.getContent()['predecessor']); return Boolean(mxEvent.getContent()['predecessor']);
} else if (handler === JSONEventFactory) { } else if (handler === JSONEventFactory) {
return false; return false;