Merge pull request #6001 from jaiwanth-v/save-edited-state-messages
Save edited state of a message when switching rooms
This commit is contained in:
commit
2d2c0d54c0
2 changed files with 67 additions and 3 deletions
|
@ -34,6 +34,7 @@ import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResiz
|
||||||
import DMRoomMap from "../../utils/DMRoomMap";
|
import DMRoomMap from "../../utils/DMRoomMap";
|
||||||
import NewRoomIntro from "../views/rooms/NewRoomIntro";
|
import NewRoomIntro from "../views/rooms/NewRoomIntro";
|
||||||
import {replaceableComponent} from "../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../utils/replaceableComponent";
|
||||||
|
import defaultDispatcher from '../../dispatcher/dispatcher';
|
||||||
|
|
||||||
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
|
||||||
const continuedTypes = ['m.sticker', 'm.room.message'];
|
const continuedTypes = ['m.sticker', 'm.room.message'];
|
||||||
|
@ -471,6 +472,10 @@ export default class MessagePanel extends React.Component {
|
||||||
return {nextEvent, nextTile};
|
return {nextEvent, nextTile};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _roomHasPendingEdit() {
|
||||||
|
return localStorage.getItem(`mx_edit_room_${this.props.room.roomId}`);
|
||||||
|
}
|
||||||
|
|
||||||
_getEventTiles() {
|
_getEventTiles() {
|
||||||
this.eventNodes = {};
|
this.eventNodes = {};
|
||||||
|
|
||||||
|
@ -559,6 +564,13 @@ export default class MessagePanel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.props.editState && this._roomHasPendingEdit) {
|
||||||
|
defaultDispatcher.dispatch({
|
||||||
|
action: "edit_event",
|
||||||
|
event: this.props.room.findEventById(this._roomHasPendingEdit),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (grouper) {
|
if (grouper) {
|
||||||
ret.push(...grouper.getTiles());
|
ret.push(...grouper.getTiles());
|
||||||
}
|
}
|
||||||
|
@ -574,7 +586,6 @@ export default class MessagePanel extends React.Component {
|
||||||
|
|
||||||
const isEditing = this.props.editState &&
|
const isEditing = this.props.editState &&
|
||||||
this.props.editState.getEvent().getId() === mxEv.getId();
|
this.props.editState.getEvent().getId() === mxEv.getId();
|
||||||
|
|
||||||
// local echoes have a fake date, which could even be yesterday. Treat them
|
// local echoes have a fake date, which could even be yesterday. Treat them
|
||||||
// as 'today' for the date separators.
|
// as 'today' for the date separators.
|
||||||
let ts1 = mxEv.getTs();
|
let ts1 = mxEv.getTs();
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {Action} from "../../../dispatcher/actions";
|
||||||
import CountlyAnalytics from "../../../CountlyAnalytics";
|
import CountlyAnalytics from "../../../CountlyAnalytics";
|
||||||
import {getKeyBindingsManager, MessageComposerAction} from '../../../KeyBindingsManager';
|
import {getKeyBindingsManager, MessageComposerAction} from '../../../KeyBindingsManager';
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
|
import SendHistoryManager from '../../../SendHistoryManager';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
|
||||||
function _isReply(mxEvent) {
|
function _isReply(mxEvent) {
|
||||||
|
@ -122,6 +123,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
saveDisabled: true,
|
saveDisabled: true,
|
||||||
};
|
};
|
||||||
this._createEditorModel();
|
this._createEditorModel();
|
||||||
|
window.addEventListener("beforeunload", this._saveStoredEditorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setEditorRef = ref => {
|
_setEditorRef = ref => {
|
||||||
|
@ -175,11 +177,55 @@ export default class EditMessageComposer extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _editorRoomKey() {
|
||||||
|
return `mx_edit_room_${this._getRoom().roomId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _editorStateKey() {
|
||||||
|
return `mx_edit_state_${this.props.editState.getEvent().getId()}`;
|
||||||
|
}
|
||||||
|
|
||||||
_cancelEdit = () => {
|
_cancelEdit = () => {
|
||||||
|
this._clearStoredEditorState();
|
||||||
dis.dispatch({action: "edit_event", event: null});
|
dis.dispatch({action: "edit_event", event: null});
|
||||||
dis.fire(Action.FocusComposer);
|
dis.fire(Action.FocusComposer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _shouldSaveStoredEditorState() {
|
||||||
|
return localStorage.getItem(this._editorRoomKey) !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_restoreStoredEditorState(partCreator) {
|
||||||
|
const json = localStorage.getItem(this._editorStateKey);
|
||||||
|
if (json) {
|
||||||
|
try {
|
||||||
|
const {parts: serializedParts} = JSON.parse(json);
|
||||||
|
const parts = serializedParts.map(p => partCreator.deserializePart(p));
|
||||||
|
return parts;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error parsing editing state: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearStoredEditorState() {
|
||||||
|
localStorage.removeItem(this._editorRoomKey);
|
||||||
|
localStorage.removeItem(this._editorStateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
_clearPreviousEdit() {
|
||||||
|
if (localStorage.getItem(this._editorRoomKey)) {
|
||||||
|
localStorage.removeItem(`mx_edit_state_${localStorage.getItem(this._editorRoomKey)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveStoredEditorState() {
|
||||||
|
const item = SendHistoryManager.createItem(this.model);
|
||||||
|
this._clearPreviousEdit();
|
||||||
|
localStorage.setItem(this._editorRoomKey, this.props.editState.getEvent().getId());
|
||||||
|
localStorage.setItem(this._editorStateKey, JSON.stringify(item));
|
||||||
|
}
|
||||||
|
|
||||||
_isSlashCommand() {
|
_isSlashCommand() {
|
||||||
const parts = this.model.parts;
|
const parts = this.model.parts;
|
||||||
const firstPart = parts[0];
|
const firstPart = parts[0];
|
||||||
|
@ -266,6 +312,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
const editedEvent = this.props.editState.getEvent();
|
const editedEvent = this.props.editState.getEvent();
|
||||||
const editContent = createEditContent(this.model, editedEvent);
|
const editContent = createEditContent(this.model, editedEvent);
|
||||||
const newContent = editContent["m.new_content"];
|
const newContent = editContent["m.new_content"];
|
||||||
|
|
||||||
let shouldSend = true;
|
let shouldSend = true;
|
||||||
|
|
||||||
// If content is modified then send an updated event into the room
|
// If content is modified then send an updated event into the room
|
||||||
|
@ -311,6 +358,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
if (shouldSend) {
|
if (shouldSend) {
|
||||||
this._cancelPreviousPendingEdit();
|
this._cancelPreviousPendingEdit();
|
||||||
const prom = this.context.sendMessage(roomId, editContent);
|
const prom = this.context.sendMessage(roomId, editContent);
|
||||||
|
this._clearStoredEditorState();
|
||||||
dis.dispatch({action: "message_sent"});
|
dis.dispatch({action: "message_sent"});
|
||||||
CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
|
CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, true, false, editContent);
|
||||||
}
|
}
|
||||||
|
@ -346,6 +394,10 @@ export default class EditMessageComposer extends React.Component {
|
||||||
// then when mounting the editor again with the same editor state,
|
// then when mounting the editor again with the same editor state,
|
||||||
// it will set the cursor at the end.
|
// it will set the cursor at the end.
|
||||||
this.props.editState.setEditorState(caret, parts);
|
this.props.editState.setEditorState(caret, parts);
|
||||||
|
window.removeEventListener("beforeunload", this._saveStoredEditorState);
|
||||||
|
if (this._shouldSaveStoredEditorState) {
|
||||||
|
this._saveStoredEditorState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_createEditorModel() {
|
_createEditorModel() {
|
||||||
|
@ -358,10 +410,11 @@ export default class EditMessageComposer extends React.Component {
|
||||||
// restore serialized parts from the state
|
// restore serialized parts from the state
|
||||||
parts = editState.getSerializedParts().map(p => partCreator.deserializePart(p));
|
parts = editState.getSerializedParts().map(p => partCreator.deserializePart(p));
|
||||||
} else {
|
} else {
|
||||||
// otherwise, parse the body of the event
|
//otherwise, either restore serialized parts from localStorage or parse the body of the event
|
||||||
parts = parseEvent(editState.getEvent(), partCreator);
|
parts = this._restoreStoredEditorState(partCreator) || parseEvent(editState.getEvent(), partCreator);
|
||||||
}
|
}
|
||||||
this.model = new EditorModel(parts, partCreator);
|
this.model = new EditorModel(parts, partCreator);
|
||||||
|
this._saveStoredEditorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
_getInitialCaretPosition() {
|
_getInitialCaretPosition() {
|
||||||
|
|
Loading…
Reference in a new issue