From 2596281a7c5aba1c6a1e13713b52fd96c78c7f5b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 6 Sep 2019 11:09:01 +0200 Subject: [PATCH] update last caret from update callback instead of input event many editor updates are not caused by an input event, so the last caret wasn't always up to date. Updating the caret from the update callback ensures that every time the editor contents is changed, the last caret is updated. --- .../views/rooms/BasicMessageComposer.js | 17 ++++++++++------- src/editor/position.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index c5661e561c..2764a8da46 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -116,6 +116,9 @@ export default class BasicMessageEditor extends React.Component { } catch (err) { console.error(err); } + // if caret is a range, take the end position + const position = caret.end || caret; + this._setLastCaretFromPosition(position); } if (this.props.placeholder) { const {isEmpty} = this.props.model; @@ -165,7 +168,6 @@ export default class BasicMessageEditor extends React.Component { this._modifiedFlag = true; const sel = document.getSelection(); const {caret, text} = getCaretOffsetAndText(this._editorRef, sel); - this._setLastCaret(caret, text, sel); this.props.model.update(text, event.inputType, caret); } @@ -183,10 +185,11 @@ export default class BasicMessageEditor extends React.Component { // we don't need to. But if the user is navigating the caret without input // we need to recalculate it, to be able to know where to insert content after // losing focus - _setLastCaret(caret, text, selection) { - this._lastSelection = cloneSelection(selection); - this._lastCaret = caret; - this._lastTextLength = text.length; + _setLastCaretFromPosition(position) { + const {model} = this.props; + this._isCaretAtEnd = position.isAtEnd(model); + this._lastCaret = position.asOffset(model); + this._lastSelection = cloneSelection(document.getSelection()); } _refreshLastCaretIfNeeded() { @@ -201,7 +204,7 @@ export default class BasicMessageEditor extends React.Component { this._lastSelection = cloneSelection(selection); const {caret, text} = getCaretOffsetAndText(this._editorRef, selection); this._lastCaret = caret; - this._lastTextLength = text.length; + this._isCaretAtEnd = caret.offset === text.length; } return this._lastCaret; } @@ -223,7 +226,7 @@ export default class BasicMessageEditor extends React.Component { } isCaretAtEnd() { - return this.getCaret().offset === this._lastTextLength; + return this._isCaretAtEnd; } _onBlur = () => { diff --git a/src/editor/position.js b/src/editor/position.js index 98b158e547..4693f62999 100644 --- a/src/editor/position.js +++ b/src/editor/position.js @@ -120,4 +120,17 @@ export default class DocumentPosition { const atEnd = offset >= lastPart.text.length; return new DocumentOffset(offset, atEnd); } + + isAtEnd(model) { + if (model.parts.length === 0) { + return true; + } + const lastPartIdx = model.parts.length - 1; + const lastPart = model.parts[lastPartIdx]; + return this.index === lastPartIdx && this.offset === lastPart.text.length; + } + + isAtStart() { + return this.index === 0 && this.offset === 0; + } }