use EditorStateTransfer to pass on state to newly mounted editor
							parent
							
								
									e674f39e3b
								
							
						
					
					
						commit
						41e41269dc
					
				|  | @ -517,7 +517,8 @@ module.exports = React.createClass({ | |||
|         const DateSeparator = sdk.getComponent('messages.DateSeparator'); | ||||
|         const ret = []; | ||||
| 
 | ||||
|         const isEditing = this.props.editEvent && this.props.editEvent.getId() === mxEv.getId(); | ||||
|         const isEditing = this.props.editState && | ||||
|             this.props.editState.getEvent().getId() === mxEv.getId(); | ||||
|         // is this a continuation of the previous message?
 | ||||
|         let continuation = false; | ||||
| 
 | ||||
|  | @ -585,7 +586,7 @@ module.exports = React.createClass({ | |||
|                     continuation={continuation} | ||||
|                     isRedacted={mxEv.isRedacted()} | ||||
|                     replacingEventId={mxEv.replacingEventId()} | ||||
|                     isEditing={isEditing} | ||||
|                     editState={isEditing && this.props.editState} | ||||
|                     onHeightChanged={this._onHeightChanged} | ||||
|                     readReceipts={readReceipts} | ||||
|                     readReceiptMap={this._readReceiptMap} | ||||
|  |  | |||
|  | @ -35,6 +35,7 @@ const Modal = require("../../Modal"); | |||
| const UserActivity = require("../../UserActivity"); | ||||
| import { KeyCode } from '../../Keyboard'; | ||||
| import Timer from '../../utils/Timer'; | ||||
| import EditorStateTransfer from '../../utils/EditorStateTransfer'; | ||||
| 
 | ||||
| const PAGINATE_SIZE = 20; | ||||
| const INITIAL_SIZE = 20; | ||||
|  | @ -411,7 +412,8 @@ const TimelinePanel = React.createClass({ | |||
|             this.forceUpdate(); | ||||
|         } | ||||
|         if (payload.action === "edit_event") { | ||||
|             this.setState({editEvent: payload.event}, () => { | ||||
|             const editState = payload.event ? new EditorStateTransfer(payload.event) : null; | ||||
|             this.setState({editState}, () => { | ||||
|                 if (payload.event && this.refs.messagePanel) { | ||||
|                     this.refs.messagePanel.scrollToEventIfNeeded( | ||||
|                         payload.event.getId(), | ||||
|  | @ -1306,7 +1308,7 @@ const TimelinePanel = React.createClass({ | |||
|                 tileShape={this.props.tileShape} | ||||
|                 resizeNotifier={this.props.resizeNotifier} | ||||
|                 getRelationsForEvent={this.getRelationsForEvent} | ||||
|                 editEvent={this.state.editEvent} | ||||
|                 editState={this.state.editState} | ||||
|                 showReactions={this.props.showReactions} | ||||
|             /> | ||||
|         ); | ||||
|  |  | |||
|  | @ -28,13 +28,14 @@ import {parseEvent} from '../../../editor/deserialize'; | |||
| import Autocomplete from '../rooms/Autocomplete'; | ||||
| import {PartCreator} from '../../../editor/parts'; | ||||
| import {renderModel} from '../../../editor/render'; | ||||
| import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; | ||||
| import EditorStateTransfer from '../../../utils/EditorStateTransfer'; | ||||
| import {MatrixClient} from 'matrix-js-sdk'; | ||||
| import classNames from 'classnames'; | ||||
| 
 | ||||
| export default class MessageEditor extends React.Component { | ||||
|     static propTypes = { | ||||
|         // the message event being edited
 | ||||
|         event: PropTypes.instanceOf(MatrixEvent).isRequired, | ||||
|         editState: PropTypes.instanceOf(EditorStateTransfer).isRequired, | ||||
|     }; | ||||
| 
 | ||||
|     static contextTypes = { | ||||
|  | @ -44,16 +45,7 @@ export default class MessageEditor extends React.Component { | |||
|     constructor(props, context) { | ||||
|         super(props, context); | ||||
|         const room = this._getRoom(); | ||||
|         const partCreator = new PartCreator( | ||||
|             () => this._autocompleteRef, | ||||
|             query => this.setState({query}), | ||||
|             room, | ||||
|         ); | ||||
|         this.model = new EditorModel( | ||||
|             parseEvent(this.props.event, room), | ||||
|             partCreator, | ||||
|             this._updateEditorState, | ||||
|         ); | ||||
|         this.model = null; | ||||
|         this.state = { | ||||
|             autoComplete: null, | ||||
|             room, | ||||
|  | @ -64,7 +56,7 @@ export default class MessageEditor extends React.Component { | |||
|     } | ||||
| 
 | ||||
|     _getRoom() { | ||||
|         return this.context.matrixClient.getRoom(this.props.event.getRoomId()); | ||||
|         return this.context.matrixClient.getRoom(this.props.editState.getEvent().getRoomId()); | ||||
|     } | ||||
| 
 | ||||
|     _updateEditorState = (caret) => { | ||||
|  | @ -133,7 +125,7 @@ export default class MessageEditor extends React.Component { | |||
|             if (this._hasModifications || !this._isCaretAtStart()) { | ||||
|                 return; | ||||
|             } | ||||
|             const previousEvent = findEditableEvent(this._getRoom(), false, this.props.event.getId()); | ||||
|             const previousEvent = findEditableEvent(this._getRoom(), false, this.props.editState.getEvent().getId()); | ||||
|             if (previousEvent) { | ||||
|                 dis.dispatch({action: 'edit_event', event: previousEvent}); | ||||
|                 event.preventDefault(); | ||||
|  | @ -142,7 +134,7 @@ export default class MessageEditor extends React.Component { | |||
|             if (this._hasModifications || !this._isCaretAtEnd()) { | ||||
|                 return; | ||||
|             } | ||||
|             const nextEvent = findEditableEvent(this._getRoom(), true, this.props.event.getId()); | ||||
|             const nextEvent = findEditableEvent(this._getRoom(), true, this.props.editState.getEvent().getId()); | ||||
|             if (nextEvent) { | ||||
|                 dis.dispatch({action: 'edit_event', event: nextEvent}); | ||||
|             } else { | ||||
|  | @ -178,11 +170,11 @@ export default class MessageEditor extends React.Component { | |||
|             "m.new_content": newContent, | ||||
|             "m.relates_to": { | ||||
|                 "rel_type": "m.replace", | ||||
|                 "event_id": this.props.event.getId(), | ||||
|                 "event_id": this.props.editState.getEvent().getId(), | ||||
|             }, | ||||
|         }, contentBody); | ||||
| 
 | ||||
|         const roomId = this.props.event.getRoomId(); | ||||
|         const roomId = this.props.editState.getEvent().getRoomId(); | ||||
|         this.context.matrixClient.sendMessage(roomId, content); | ||||
| 
 | ||||
|         dis.dispatch({action: "edit_event", event: null}); | ||||
|  | @ -197,12 +189,63 @@ export default class MessageEditor extends React.Component { | |||
|         this.model.autoComplete.onComponentSelectionChange(completion); | ||||
|     } | ||||
| 
 | ||||
|     componentWillUnmount() { | ||||
|         const sel = document.getSelection(); | ||||
|         const {caret} = getCaretOffsetAndText(this._editorRef, sel); | ||||
|         const parts = this.model.serializeParts(); | ||||
|         this.props.editState.setEditorState(caret, parts); | ||||
|     } | ||||
| 
 | ||||
|     componentDidMount() { | ||||
|         this.model = this._createEditorModel(); | ||||
|         // initial render of model
 | ||||
|         this._updateEditorState(); | ||||
|         setCaretPosition(this._editorRef, this.model, this.model.getPositionAtEnd()); | ||||
|         // initial caret position
 | ||||
|         this._initializeCaret(); | ||||
|         this._editorRef.focus(); | ||||
|     } | ||||
| 
 | ||||
|     _createEditorModel() { | ||||
|         const {editState} = this.props; | ||||
|         const room = this._getRoom(); | ||||
|         const partCreator = new PartCreator( | ||||
|             () => this._autocompleteRef, | ||||
|             query => this.setState({query}), | ||||
|             room, | ||||
|             this.context.matrixClient, | ||||
|         ); | ||||
|         let parts; | ||||
|         if (editState.hasEditorState()) { | ||||
|             // if restoring state from a previous editor,
 | ||||
|             // restore serialized parts from the state
 | ||||
|             parts = editState.getSerializedParts().map(p => partCreator.deserializePart(p)); | ||||
|         } else { | ||||
|             // otherwise, parse the body of the event
 | ||||
|             parts = parseEvent(editState.getEvent(), room, this.context.matrixClient); | ||||
|         } | ||||
| 
 | ||||
|         return new EditorModel( | ||||
|             parts, | ||||
|             partCreator, | ||||
|             this._updateEditorState, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     _initializeCaret() { | ||||
|         const {editState} = this.props; | ||||
|         let caretPosition; | ||||
|         if (editState.hasEditorState()) { | ||||
|             // if restoring state from a previous editor,
 | ||||
|             // restore caret position from the state
 | ||||
|             const caret = editState.getCaret(); | ||||
|             caretPosition = this.model.positionForOffset(caret.offset, caret.atNodeEnd); | ||||
|         } else { | ||||
|             // otherwise, set it at the end
 | ||||
|             caretPosition = this.model.getPositionAtEnd(); | ||||
|         } | ||||
|         setCaretPosition(this._editorRef, this.model, caretPosition); | ||||
|     } | ||||
| 
 | ||||
|     render() { | ||||
|         let autoComplete; | ||||
|         if (this.state.autoComplete) { | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ module.exports = React.createClass({ | |||
|             tileShape={this.props.tileShape} | ||||
|             maxImageHeight={this.props.maxImageHeight} | ||||
|             replacingEventId={this.props.replacingEventId} | ||||
|             isEditing={this.props.isEditing} | ||||
|             editState={this.props.editState} | ||||
|             onHeightChanged={this.props.onHeightChanged} />; | ||||
|     }, | ||||
| }); | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ module.exports = React.createClass({ | |||
| 
 | ||||
|     componentDidMount: function() { | ||||
|         this._unmounted = false; | ||||
|         if (!this.props.isEditing) { | ||||
|         if (!this.props.editState) { | ||||
|             this._applyFormatting(); | ||||
|         } | ||||
|     }, | ||||
|  | @ -131,8 +131,8 @@ module.exports = React.createClass({ | |||
|     }, | ||||
| 
 | ||||
|     componentDidUpdate: function(prevProps) { | ||||
|         if (!this.props.isEditing) { | ||||
|             const stoppedEditing = prevProps.isEditing && !this.props.isEditing; | ||||
|         if (!this.props.editState) { | ||||
|             const stoppedEditing = prevProps.editState && !this.props.editState; | ||||
|             const messageWasEdited = prevProps.replacingEventId !== this.props.replacingEventId; | ||||
|             if (messageWasEdited || stoppedEditing) { | ||||
|                 this._applyFormatting(); | ||||
|  | @ -153,7 +153,7 @@ module.exports = React.createClass({ | |||
|                 nextProps.replacingEventId !== this.props.replacingEventId || | ||||
|                 nextProps.highlightLink !== this.props.highlightLink || | ||||
|                 nextProps.showUrlPreview !== this.props.showUrlPreview || | ||||
|                 nextProps.isEditing !== this.props.isEditing || | ||||
|                 nextProps.editState !== this.props.editState || | ||||
|                 nextState.links !== this.state.links || | ||||
|                 nextState.editedMarkerHovered !== this.state.editedMarkerHovered || | ||||
|                 nextState.widgetHidden !== this.state.widgetHidden); | ||||
|  | @ -469,9 +469,9 @@ module.exports = React.createClass({ | |||
|     }, | ||||
| 
 | ||||
|     render: function() { | ||||
|         if (this.props.isEditing) { | ||||
|         if (this.props.editState) { | ||||
|             const MessageEditor = sdk.getComponent('elements.MessageEditor'); | ||||
|             return <MessageEditor event={this.props.mxEvent} className="mx_EventTile_content" />; | ||||
|             return <MessageEditor editState={this.props.editState} className="mx_EventTile_content" />; | ||||
|         } | ||||
|         const mxEvent = this.props.mxEvent; | ||||
|         const content = mxEvent.getContent(); | ||||
|  |  | |||
|  | @ -552,13 +552,14 @@ module.exports = withMatrixClient(React.createClass({ | |||
|         const isRedacted = isMessageEvent(this.props.mxEvent) && this.props.isRedacted; | ||||
|         const isEncryptionFailure = this.props.mxEvent.isDecryptionFailure(); | ||||
| 
 | ||||
|         const isEditing = !!this.props.editState; | ||||
|         const classes = classNames({ | ||||
|             mx_EventTile: true, | ||||
|             mx_EventTile_isEditing: this.props.isEditing, | ||||
|             mx_EventTile_isEditing: isEditing, | ||||
|             mx_EventTile_info: isInfoMessage, | ||||
|             mx_EventTile_12hr: this.props.isTwelveHour, | ||||
|             mx_EventTile_encrypting: this.props.eventSendStatus === 'encrypting', | ||||
|             mx_EventTile_sending: isSending, | ||||
|             mx_EventTile_sending: !isEditing && isSending, | ||||
|             mx_EventTile_notSent: this.props.eventSendStatus === 'not_sent', | ||||
|             mx_EventTile_highlight: this.props.tileShape === 'notif' ? false : this.shouldHighlight(), | ||||
|             mx_EventTile_selected: this.props.isSelectedEvent, | ||||
|  | @ -632,7 +633,7 @@ module.exports = withMatrixClient(React.createClass({ | |||
|         } | ||||
| 
 | ||||
|         const MessageActionBar = sdk.getComponent('messages.MessageActionBar'); | ||||
|         const actionBar = !this.props.isEditing ? <MessageActionBar | ||||
|         const actionBar = !isEditing ? <MessageActionBar | ||||
|             mxEvent={this.props.mxEvent} | ||||
|             reactions={this.state.reactions} | ||||
|             permalinkCreator={this.props.permalinkCreator} | ||||
|  | @ -794,7 +795,7 @@ module.exports = withMatrixClient(React.createClass({ | |||
|                             <EventTileType ref="tile" | ||||
|                                            mxEvent={this.props.mxEvent} | ||||
|                                            replacingEventId={this.props.replacingEventId} | ||||
|                                            isEditing={this.props.isEditing} | ||||
|                                            editState={this.props.editState} | ||||
|                                            highlights={this.props.highlights} | ||||
|                                            highlightLink={this.props.highlightLink} | ||||
|                                            showUrlPreview={this.props.showUrlPreview} | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ export default class EditorModel { | |||
| 
 | ||||
|     update(newValue, inputType, caret) { | ||||
|         const diff = this._diff(newValue, inputType, caret); | ||||
|         const position = this._positionForOffset(diff.at, caret.atNodeEnd); | ||||
|         const position = this.positionForOffset(diff.at, caret.atNodeEnd); | ||||
|         let removedOffsetDecrease = 0; | ||||
|         if (diff.removed) { | ||||
|             removedOffsetDecrease = this._removeText(position, diff.removed.length); | ||||
|  | @ -99,7 +99,7 @@ export default class EditorModel { | |||
|         } | ||||
|         this._mergeAdjacentParts(); | ||||
|         const caretOffset = diff.at - removedOffsetDecrease + addedLen; | ||||
|         let newPosition = this._positionForOffset(caretOffset, true); | ||||
|         let newPosition = this.positionForOffset(caretOffset, true); | ||||
|         newPosition = newPosition.skipUneditableParts(this._parts); | ||||
|         this._setActivePart(newPosition); | ||||
|         this._updateCallback(newPosition); | ||||
|  | @ -248,7 +248,7 @@ export default class EditorModel { | |||
|         return addLen; | ||||
|     } | ||||
| 
 | ||||
|     _positionForOffset(totalOffset, atPartEnd) { | ||||
|     positionForOffset(totalOffset, atPartEnd) { | ||||
|         let currentOffset = 0; | ||||
|         const index = this._parts.findIndex(part => { | ||||
|             const partLen = part.text.length; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Bruno Windels
						Bruno Windels