Merge pull request #2983 from matrix-org/bwindels/editor-cursor-fixes
Message editing: fix some bugs in cursor behaviour
This commit is contained in:
commit
9744cbd448
3 changed files with 50 additions and 22 deletions
|
@ -144,12 +144,7 @@ export default class MessageEditor extends React.Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this._updateEditorState();
|
this._updateEditorState();
|
||||||
const sel = document.getSelection();
|
setCaretPosition(this._editorRef, this.model, this.model.getPositionAtEnd());
|
||||||
const range = document.createRange();
|
|
||||||
range.selectNodeContents(this._editorRef);
|
|
||||||
range.collapse(false);
|
|
||||||
sel.removeAllRanges();
|
|
||||||
sel.addRange(range);
|
|
||||||
this._editorRef.focus();
|
this._editorRef.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,16 @@ export default class EditorModel {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPositionAtEnd() {
|
||||||
|
if (this._parts.length) {
|
||||||
|
const index = this._parts.length - 1;
|
||||||
|
const part = this._parts[index];
|
||||||
|
return new DocumentPosition(index, part.text.length);
|
||||||
|
} else {
|
||||||
|
return new DocumentPosition(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serializeParts() {
|
serializeParts() {
|
||||||
return this._parts.map(({type, text}) => {return {type, text};});
|
return this._parts.map(({type, text}) => {return {type, text};});
|
||||||
}
|
}
|
||||||
|
@ -88,7 +98,8 @@ export default class EditorModel {
|
||||||
}
|
}
|
||||||
this._mergeAdjacentParts();
|
this._mergeAdjacentParts();
|
||||||
const caretOffset = diff.at - removedOffsetDecrease + addedLen;
|
const caretOffset = diff.at - removedOffsetDecrease + addedLen;
|
||||||
const newPosition = this._positionForOffset(caretOffset, true);
|
let newPosition = this._positionForOffset(caretOffset, true);
|
||||||
|
newPosition = newPosition.skipUneditableParts(this._parts);
|
||||||
this._setActivePart(newPosition);
|
this._setActivePart(newPosition);
|
||||||
this._updateCallback(newPosition);
|
this._updateCallback(newPosition);
|
||||||
}
|
}
|
||||||
|
@ -172,6 +183,8 @@ export default class EditorModel {
|
||||||
// part might be undefined here
|
// part might be undefined here
|
||||||
let part = this._parts[index];
|
let part = this._parts[index];
|
||||||
const amount = Math.min(len, part.text.length - offset);
|
const amount = Math.min(len, part.text.length - offset);
|
||||||
|
// don't allow 0 amount deletions
|
||||||
|
if (amount) {
|
||||||
if (part.canEdit) {
|
if (part.canEdit) {
|
||||||
const replaceWith = part.remove(offset, amount);
|
const replaceWith = part.remove(offset, amount);
|
||||||
if (typeof replaceWith === "string") {
|
if (typeof replaceWith === "string") {
|
||||||
|
@ -188,6 +201,9 @@ export default class EditorModel {
|
||||||
removedOffsetDecrease += offset;
|
removedOffsetDecrease += offset;
|
||||||
this._removePart(index);
|
this._removePart(index);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
len -= amount;
|
len -= amount;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
@ -261,4 +277,13 @@ class DocumentPosition {
|
||||||
get offset() {
|
get offset() {
|
||||||
return this._offset;
|
return this._offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skipUneditableParts(parts) {
|
||||||
|
const part = parts[this.index];
|
||||||
|
if (part && !part.canEdit) {
|
||||||
|
return new DocumentPosition(this.index + 1, 0);
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ class BasePart {
|
||||||
appendUntilRejected(str) {
|
appendUntilRejected(str) {
|
||||||
for (let i = 0; i < str.length; ++i) {
|
for (let i = 0; i < str.length; ++i) {
|
||||||
const chr = str.charAt(i);
|
const chr = str.charAt(i);
|
||||||
if (!this.acceptsInsertion(chr)) {
|
if (!this.acceptsInsertion(chr, i)) {
|
||||||
this._text = this._text + str.substr(0, i);
|
this._text = this._text + str.substr(0, i);
|
||||||
return str.substr(i);
|
return str.substr(i);
|
||||||
}
|
}
|
||||||
|
@ -180,8 +180,8 @@ class PillPart extends BasePart {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NewlinePart extends BasePart {
|
export class NewlinePart extends BasePart {
|
||||||
acceptsInsertion(chr) {
|
acceptsInsertion(chr, i) {
|
||||||
return this.text.length === 0 && chr === "\n";
|
return (this.text.length + i) === 0 && chr === "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsRemoval(position, chr) {
|
acceptsRemoval(position, chr) {
|
||||||
|
@ -205,6 +205,14 @@ export class NewlinePart extends BasePart {
|
||||||
get type() {
|
get type() {
|
||||||
return "newline";
|
return "newline";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this makes the cursor skip this part when it is inserted
|
||||||
|
// rather than trying to append to it, which is what we want.
|
||||||
|
// As a newline can also be only one character, it makes sense
|
||||||
|
// as it can only be one character long. This caused #9741.
|
||||||
|
get canEdit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RoomPillPart extends PillPart {
|
export class RoomPillPart extends PillPart {
|
||||||
|
|
Loading…
Reference in a new issue