Implement MessageComposerStore to persist composer state across room switching

This behaviour was present in the old composer but implemented using local storage. This is unecessary as we don't really care about our drafts across clients, the important thing is that our draft is kept when switching rooms.

As a bonus, ifnore vertical arrow key presses when a modifier key is pressed so that the room switching keys (alt + up/down arrow) don't also cause history browsing (or autocomplete browsing).
pull/21833/head
Luke Barnard 2017-07-05 10:24:55 +01:00
parent 0af77e8913
commit 084a933dbd
2 changed files with 92 additions and 0 deletions

View File

@ -43,6 +43,8 @@ import Markdown from '../../../Markdown';
import ComposerHistoryManager from '../../../ComposerHistoryManager';
import {onSendMessageFailed} from './MessageComposerInputOld';
import MessageComposerStore from '../../../stores/MessageComposerStore';
const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000;
const ZWS_CODE = 8203;
@ -170,6 +172,11 @@ export default class MessageComposerInput extends React.Component {
componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
this.historyManager = new ComposerHistoryManager(this.props.room.roomId);
// Reinstate the editor state for this room
this.setState({
editorState: MessageComposerStore.getEditorState(this.props.room.roomId),
});
}
componentWillUnmount() {
@ -336,6 +343,14 @@ export default class MessageComposerInput extends React.Component {
this.onFinishedTyping();
}
// Record the editor state for this room so that it can be retrieved after
// switching to another room and back
dis.dispatch({
action: 'editor_state',
room_id: this.props.room.roomId,
editor_state: state.editorState,
});
if (!state.hasOwnProperty('originalEditorState')) {
state.originalEditorState = null;
}
@ -632,6 +647,10 @@ export default class MessageComposerInput extends React.Component {
};
onVerticalArrow = (e, up) => {
if (e.ctrlKey || e.shiftKey || e.altKey || e.metaKey) {
return;
}
// Select history only if we are not currently auto-completing
if (this.autocomplete.state.completionList.length === 0) {
// Don't go back in history if we're in the middle of a multi-line message

View File

@ -0,0 +1,73 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dis from '../dispatcher';
import {Store} from 'flux/utils';
const INITIAL_STATE = {
editorStateMap: {},
};
/**
* A class for storing application state to do with the message composer. This is a simple
* flux store that listens for actions and updates its state accordingly, informing any
* listeners (views) of state changes.
*/
class MessageComposerStore extends Store {
constructor() {
super(dis);
// Initialise state
this._state = INITIAL_STATE;
}
_setState(newState) {
this._state = Object.assign(this._state, newState);
this.__emitChange();
}
__onDispatch(payload) {
switch (payload.action) {
case 'editor_state':
this._editorState(payload);
break;
case 'on_logged_out':
this.reset();
break;
}
}
_editorState(payload) {
const editorStateMap = this._state.editorStateMap;
editorStateMap[payload.room_id] = payload.editor_state;
this._setState({
editorStateMap: editorStateMap,
});
}
getEditorState(roomId) {
return this._state.editorStateMap[roomId];
}
reset() {
this._state = Object.assign({}, INITIAL_STATE);
}
}
let singletonMessageComposerStore = null;
if (!singletonMessageComposerStore) {
singletonMessageComposerStore = new MessageComposerStore();
}
module.exports = singletonMessageComposerStore;