From 2ea556e0b40897fb92785a956f1b97baa204d41e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 4 Sep 2019 16:04:06 +0200 Subject: [PATCH] support update callback setting selection instead of caret --- .../views/rooms/BasicMessageComposer.js | 10 +++--- src/editor/caret.js | 33 ++++++++++++++++--- src/editor/model.js | 7 +++- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index b1eb4f0746..3f07cf567e 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import EditorModel from '../../../editor/model'; import HistoryManager from '../../../editor/history'; -import {setCaretPosition} from '../../../editor/caret'; +import {setSelection} from '../../../editor/caret'; import { formatRangeAsQuote, formatRangeAsCode, @@ -115,11 +115,11 @@ export default class BasicMessageEditor extends React.Component { } } - _updateEditorState = (caret, inputType, diff) => { + _updateEditorState = (selection, inputType, diff) => { renderModel(this._editorRef, this.props.model); - if (caret) { + if (selection) { // set the caret/selection try { - setCaretPosition(this._editorRef, this.props.model, caret); + setSelection(this._editorRef, this.props.model, selection); } catch (err) { console.error(err); } @@ -133,7 +133,7 @@ export default class BasicMessageEditor extends React.Component { } } this.setState({autoComplete: this.props.model.autoComplete}); - this.historyManager.tryPush(this.props.model, caret, inputType, diff); + this.historyManager.tryPush(this.props.model, selection, inputType, diff); TypingStore.sharedInstance().setSelfTyping(this.props.room.roomId, !this.props.model.isEmpty); if (this.props.onChange) { diff --git a/src/editor/caret.js b/src/editor/caret.js index 9b0fa14cfc..ed4f1b2a2e 100644 --- a/src/editor/caret.js +++ b/src/editor/caret.js @@ -16,12 +16,39 @@ limitations under the License. */ import {needsCaretNodeBefore, needsCaretNodeAfter} from "./render"; +import Range from "./range"; + +export function setSelection(editor, model, selection) { + if (selection instanceof Range) { + setDocumentRangeSelection(editor, model, selection); + } else { + setCaretPosition(editor, model, selection); + } +} + +function setDocumentRangeSelection(editor, model, range) { + const sel = document.getSelection(); + sel.removeAllRanges(); + const selectionRange = document.createRange(); + const start = getNodeAndOffsetForPosition(editor, model, range.start); + selectionRange.setStart(start.node, start.offset); + const end = getNodeAndOffsetForPosition(editor, model, range.end); + selectionRange.setEnd(end.node, end.offset); + sel.addRange(selectionRange); +} export function setCaretPosition(editor, model, caretPosition) { const sel = document.getSelection(); sel.removeAllRanges(); const range = document.createRange(); - const {offset, lineIndex, nodeIndex} = getLineAndNodePosition(model, caretPosition); + const {node, offset} = getNodeAndOffsetForPosition(editor, model, caretPosition); + range.setStart(node, offset); + range.collapse(true); + sel.addRange(range); +} + +function getNodeAndOffsetForPosition(editor, model, position) { + const {offset, lineIndex, nodeIndex} = getLineAndNodePosition(model, position); const lineNode = editor.childNodes[lineIndex]; let focusNode; @@ -35,9 +62,7 @@ export function setCaretPosition(editor, model, caretPosition) { focusNode = focusNode.firstChild; } } - range.setStart(focusNode, offset); - range.collapse(true); - sel.addRange(range); + return {node: focusNode, offset}; } export function getLineAndNodePosition(model, caretPosition) { diff --git a/src/editor/model.js b/src/editor/model.js index 3b4f1ce460..ea6b05570c 100644 --- a/src/editor/model.js +++ b/src/editor/model.js @@ -433,7 +433,12 @@ export default class EditorModel { */ transform(callback) { const pos = callback(); - const acPromise = this._setActivePart(pos, true); + let acPromise = null; + if (!(pos instanceof Range)) { + acPromise = this._setActivePart(pos, true); + } else { + acPromise = Promise.resolve(); + } this._updateCallback(pos); return acPromise; }