support update callback setting selection instead of caret

This commit is contained in:
Bruno Windels 2019-09-04 16:04:06 +02:00
parent 037ac29c57
commit 2ea556e0b4
3 changed files with 40 additions and 10 deletions

View file

@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import EditorModel from '../../../editor/model'; import EditorModel from '../../../editor/model';
import HistoryManager from '../../../editor/history'; import HistoryManager from '../../../editor/history';
import {setCaretPosition} from '../../../editor/caret'; import {setSelection} from '../../../editor/caret';
import { import {
formatRangeAsQuote, formatRangeAsQuote,
formatRangeAsCode, 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); renderModel(this._editorRef, this.props.model);
if (caret) { if (selection) { // set the caret/selection
try { try {
setCaretPosition(this._editorRef, this.props.model, caret); setSelection(this._editorRef, this.props.model, selection);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@ -133,7 +133,7 @@ export default class BasicMessageEditor extends React.Component {
} }
} }
this.setState({autoComplete: this.props.model.autoComplete}); 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); TypingStore.sharedInstance().setSelfTyping(this.props.room.roomId, !this.props.model.isEmpty);
if (this.props.onChange) { if (this.props.onChange) {

View file

@ -16,12 +16,39 @@ limitations under the License.
*/ */
import {needsCaretNodeBefore, needsCaretNodeAfter} from "./render"; 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) { export function setCaretPosition(editor, model, caretPosition) {
const sel = document.getSelection(); const sel = document.getSelection();
sel.removeAllRanges(); sel.removeAllRanges();
const range = document.createRange(); 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]; const lineNode = editor.childNodes[lineIndex];
let focusNode; let focusNode;
@ -35,9 +62,7 @@ export function setCaretPosition(editor, model, caretPosition) {
focusNode = focusNode.firstChild; focusNode = focusNode.firstChild;
} }
} }
range.setStart(focusNode, offset); return {node: focusNode, offset};
range.collapse(true);
sel.addRange(range);
} }
export function getLineAndNodePosition(model, caretPosition) { export function getLineAndNodePosition(model, caretPosition) {

View file

@ -433,7 +433,12 @@ export default class EditorModel {
*/ */
transform(callback) { transform(callback) {
const pos = 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); this._updateCallback(pos);
return acPromise; return acPromise;
} }