Merge pull request #3210 from matrix-org/bwindels/prevent-autocomplete-on-paste

Prevent autocomplete on paste, and verserev-ing text before and after :
This commit is contained in:
Bruno Windels 2019-07-12 08:25:06 +00:00 committed by GitHub
commit 7fc19e61a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 9 deletions

View file

@ -280,6 +280,7 @@ export default class MessageEditor extends React.Component {
} }
componentWillUnmount() { componentWillUnmount() {
this._editorRef.removeEventListener("input", this._onInput, true);
const sel = document.getSelection(); const sel = document.getSelection();
const {caret} = getCaretOffsetAndText(this._editorRef, sel); const {caret} = getCaretOffsetAndText(this._editorRef, sel);
const parts = this.model.serializeParts(); const parts = this.model.serializeParts();
@ -292,6 +293,9 @@ export default class MessageEditor extends React.Component {
this._updateEditorState(); this._updateEditorState();
// initial caret position // initial caret position
this._initializeCaret(); this._initializeCaret();
// attach input listener by hand so React doesn't proxy the events,
// as the proxied event doesn't support inputType, which we need.
this._editorRef.addEventListener("input", this._onInput, true);
this._editorRef.focus(); this._editorRef.focus();
} }
@ -359,7 +363,6 @@ export default class MessageEditor extends React.Component {
className="mx_MessageEditor_editor" className="mx_MessageEditor_editor"
contentEditable="true" contentEditable="true"
tabIndex="1" tabIndex="1"
onInput={this._onInput}
onKeyDown={this._onKeyDown} onKeyDown={this._onKeyDown}
ref={ref => this._editorRef = ref} ref={ref => this._editorRef = ref}
aria-label={_t("Edit message")} aria-label={_t("Edit message")}

View file

@ -97,24 +97,26 @@ export default class EditorModel {
if (diff.removed) { if (diff.removed) {
removedOffsetDecrease = this.removeText(position, diff.removed.length); removedOffsetDecrease = this.removeText(position, diff.removed.length);
} }
const canOpenAutoComplete = inputType !== "insertFromPaste" && inputType !== "insertFromDrop";
let addedLen = 0; let addedLen = 0;
if (diff.added) { if (diff.added) {
addedLen = this._addText(position, diff.added); // these shouldn't trigger auto-complete, you just want to append a piece of text
addedLen = this._addText(position, diff.added, {validate: canOpenAutoComplete});
} }
this._mergeAdjacentParts(); this._mergeAdjacentParts();
const caretOffset = diff.at - removedOffsetDecrease + addedLen; const caretOffset = diff.at - removedOffsetDecrease + addedLen;
const newPosition = this.positionForOffset(caretOffset, true); const newPosition = this.positionForOffset(caretOffset, true);
this._setActivePart(newPosition); this._setActivePart(newPosition, canOpenAutoComplete);
this._updateCallback(newPosition); this._updateCallback(newPosition);
} }
_setActivePart(pos) { _setActivePart(pos, canOpenAutoComplete) {
const {index} = pos; const {index} = pos;
const part = this._parts[index]; const part = this._parts[index];
if (part) { if (part) {
if (index !== this._activePartIdx) { if (index !== this._activePartIdx) {
this._activePartIdx = index; this._activePartIdx = index;
if (this._activePartIdx !== this._autoCompletePartIdx) { if (canOpenAutoComplete && this._activePartIdx !== this._autoCompletePartIdx) {
// else try to create one // else try to create one
const ac = part.createAutoComplete(this._onAutoComplete); const ac = part.createAutoComplete(this._onAutoComplete);
if (ac) { if (ac) {
@ -217,17 +219,22 @@ export default class EditorModel {
* inserts `str` into the model at `pos`. * inserts `str` into the model at `pos`.
* @param {Object} pos * @param {Object} pos
* @param {string} str * @param {string} str
* @param {Object} options
* @param {bool} options.validate Whether characters will be validated by the part.
* Validating allows the inserted text to be parsed according to the part rules.
* @return {Number} how far from position (in characters) the insertion ended. * @return {Number} how far from position (in characters) the insertion ended.
* This can be more than the length of `str` when crossing non-editable parts, which are skipped. * This can be more than the length of `str` when crossing non-editable parts, which are skipped.
*/ */
_addText(pos, str) { _addText(pos, str, {validate=true}) {
let {index} = pos; let {index} = pos;
const {offset} = pos; const {offset} = pos;
let addLen = str.length; let addLen = str.length;
const part = this._parts[index]; const part = this._parts[index];
if (part) { if (part) {
if (part.canEdit) { if (part.canEdit) {
if (part.insertAll(offset, str)) { if (validate && part.validateAndInsert(offset, str)) {
str = null;
} else if (!validate && part.insert(offset, str)) {
str = null; str = null;
} else { } else {
const splitPart = part.split(offset); const splitPart = part.split(offset);
@ -240,10 +247,19 @@ export default class EditorModel {
addLen += part.text.length - offset; addLen += part.text.length - offset;
index += 1; index += 1;
} }
} else if (index < 0) {
// if position was not found (index: -1, as happens for empty editor)
// reset it to insert as first part
index = 0;
} }
while (str) { while (str) {
const newPart = this._partCreator.createPartForInput(str); const newPart = this._partCreator.createPartForInput(str);
if (validate) {
str = newPart.appendUntilRejected(str); str = newPart.appendUntilRejected(str);
} else {
newPart.insert(0, str);
str = null;
}
this._insertPart(index, newPart); this._insertPart(index, newPart);
index += 1; index += 1;
} }

View file

@ -69,7 +69,7 @@ class BasePart {
// inserts str at offset if all the characters in str were accepted, otherwise don't do anything // inserts str at offset if all the characters in str were accepted, otherwise don't do anything
// return whether the str was accepted or not. // return whether the str was accepted or not.
insertAll(offset, str) { validateAndInsert(offset, 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)) {
@ -82,6 +82,16 @@ class BasePart {
return true; return true;
} }
insert(offset, str) {
if (this.canEdit) {
const beforeInsert = this._text.substr(0, offset);
const afterInsert = this._text.substr(offset);
this._text = beforeInsert + str + afterInsert;
return true;
}
return false;
}
createAutoComplete() {} createAutoComplete() {}
trim(len) { trim(len) {