}
function Message({
- mEvent, isBodyOnly, roomTimeline, focus, fullTime,
+ mEvent, isBodyOnly, roomTimeline,
+ focus, fullTime, isEdit, setEdit, cancelEdit,
}) {
- const [isEditing, setIsEditing] = useState(false);
const roomId = mEvent.getRoomId();
const { editedTimeline, reactionTimeline } = roomTimeline ?? {};
const avatarSrc = mEvent.sender?.getAvatarUrl(initMatrix.matrixClient.baseUrl, 36, 36, 'crop') ?? null;
const edit = useCallback(() => {
- setIsEditing(true);
+ setEdit(eventId);
}, []);
const reply = useCallback(() => {
replyTo(senderId, mEvent.getId(), body);
eventId={mEvent.replyEventId}
/>
)}
- {!isEditing && (
+ {!isEdit && (
<MessageBody
senderName={username}
isCustomHTML={isCustomHTML}
isEdited={isEdited}
/>
)}
- {isEditing && (
+ {isEdit && (
<MessageEdit
body={body}
onSave={(newBody) => {
if (newBody !== body) {
initMatrix.roomsInput.sendEditedMessage(roomId, mEvent, newBody);
}
- setIsEditing(false);
+ cancelEdit();
}}
- onCancel={() => setIsEditing(false)}
+ onCancel={cancelEdit}
/>
)}
{haveReactions && (
<MessageReactionGroup roomTimeline={roomTimeline} mEvent={mEvent} />
)}
- {roomTimeline && !isEditing && (
+ {roomTimeline && !isEdit && (
<MessageOptions
roomTimeline={roomTimeline}
mEvent={mEvent}
focus: false,
roomTimeline: null,
fullTime: false,
+ isEdit: false,
+ setEdit: null,
+ cancelEdit: null,
};
Message.propTypes = {
mEvent: PropTypes.shape({}).isRequired,
roomTimeline: PropTypes.shape({}),
focus: PropTypes.bool,
fullTime: PropTypes.bool,
+ isEdit: PropTypes.bool,
+ setEdit: PropTypes.func,
+ cancelEdit: PropTypes.func,
};
export { Message, MessageReply, PlaceholderMessage };
}
}
-function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
+function renderEvent(
+ roomTimeline,
+ mEvent,
+ prevMEvent,
+ isFocus,
+ isEdit,
+ setEdit,
+ cancelEdit,
+) {
const isBodyOnly = (prevMEvent !== null
&& prevMEvent.getSender() === mEvent.getSender()
&& prevMEvent.getType() !== 'm.room.member'
roomTimeline={roomTimeline}
focus={isFocus}
fullTime={false}
+ isEdit={isEdit}
+ setEdit={setEdit}
+ cancelEdit={cancelEdit}
/>
);
}
const timelineSVRef = useRef(null);
const timelineScrollRef = useRef(null);
const eventLimitRef = useRef(null);
+ const [editEventId, setEditEventId] = useState(null);
+ const cancelEdit = () => setEditEventId(null);
const readUptoEvtStore = useStore(roomTimeline);
const [onLimitUpdate, forceUpdateLimit] = useForceUpdate();
}
}, [newEvent]);
+ const listenKeyboard = useCallback((event) => {
+ if (event.ctrlKey || event.altKey || event.metaKey) return;
+ if (event.key !== 'ArrowUp') return;
+ if (navigation.isRawModalVisible) return;
+
+ if (document.activeElement.id !== 'message-textarea') return;
+ if (document.activeElement.value !== '') return;
+
+ const {
+ timeline: tl, activeTimeline, liveTimeline, matrixClient: mx,
+ } = roomTimeline;
+ const limit = eventLimitRef.current;
+ if (activeTimeline !== liveTimeline) return;
+ if (tl.length > limit.length) return;
+
+ const mTypes = ['m.text'];
+ for (let i = tl.length - 1; i >= 0; i -= 1) {
+ const mE = tl[i];
+ if (
+ mE.getSender() === mx.getUserId()
+ && mE.getType() === 'm.room.message'
+ && mTypes.includes(mE.getContent()?.msgtype)
+ ) {
+ setEditEventId(mE.getId());
+ return;
+ }
+ }
+ }, [roomTimeline]);
+
+ useEffect(() => {
+ document.body.addEventListener('keydown', listenKeyboard);
+ return () => {
+ document.body.removeEventListener('keydown', listenKeyboard);
+ };
+ }, [listenKeyboard]);
+
const handleTimelineScroll = (event) => {
const timelineScroll = timelineScrollRef.current;
if (!event.target) return;
const isFocus = focusId === mEvent.getId();
if (isFocus) jumpToItemIndex = itemCountIndex;
- tl.push(renderEvent(roomTimeline, mEvent, isNewEvent ? null : prevMEvent, isFocus));
+ tl.push(renderEvent(
+ roomTimeline,
+ mEvent,
+ isNewEvent ? null : prevMEvent,
+ isFocus,
+ editEventId === mEvent.getId(),
+ setEditEventId,
+ cancelEdit,
+ ));
itemCountIndex += 1;
}
if (roomTimeline.canPaginateForward() || limit.length < timeline.length) {