FIX: Autocomplete incorrectly replacing text if used mid sentence.

* Adds test to document the behavior we were seeing.
This commit is contained in:
Alan Guo Xiang Tan 2022-01-18 13:13:04 +08:00
parent 232f840b60
commit 0aacd63436
2 changed files with 127 additions and 1 deletions

View File

@ -201,17 +201,22 @@ export default function (options) {
if (term) { if (term) {
let text = me.val(); let text = me.val();
text = text =
text.substring(0, completeStart) + text.substring(0, completeStart) +
(options.preserveKey ? options.key || "" : "") + (options.preserveKey ? options.key || "" : "") +
term + term +
" " + " " +
text.substring(completeEnd + 1, text.length); text.substring(completeEnd + 1, text.length);
me.val(text); me.val(text);
let newCaretPos = completeStart + 1 + term.length; let newCaretPos = completeStart + 1 + term.length;
if (options.key) { if (options.key) {
newCaretPos++; newCaretPos++;
} }
setCaretPosition(me[0], newCaretPos); setCaretPosition(me[0], newCaretPos);
if (options && options.afterComplete) { if (options && options.afterComplete) {
@ -487,6 +492,7 @@ export default function (options) {
if (options.key) { if (options.key) {
if (options.onKeyUp && key !== options.key) { if (options.onKeyUp && key !== options.key) {
let match = options.onKeyUp(me.val(), cp); let match = options.onKeyUp(me.val(), cp);
if (match) { if (match) {
completeStart = cp - match[0].length; completeStart = cp - match[0].length;
completeEnd = completeStart + match[0].length - 1; completeEnd = completeStart + match[0].length - 1;
@ -543,26 +549,36 @@ export default function (options) {
if (!options.key) { if (!options.key) {
completeStart = 0; completeStart = 0;
} }
if (e.which === keys.shift) { if (e.which === keys.shift) {
return; return;
} }
if (completeStart === null && e.which === keys.backSpace && options.key) { if (completeStart === null && e.which === keys.backSpace && options.key) {
c = caretPosition(me[0]); c = caretPosition(me[0]);
c -= 1; c -= 1;
initial = c; initial = c;
prevIsGood = true; prevIsGood = true;
while (prevIsGood && c >= 0) { while (prevIsGood && c >= 0) {
c -= 1; c -= 1;
prev = me[0].value[c]; prev = me[0].value[c];
stopFound = prev === options.key; stopFound = prev === options.key;
if (stopFound) { if (stopFound) {
prev = me[0].value[c - 1]; prev = me[0].value[c - 1];
if ( if (
checkTriggerRule({ backSpace: true }) && checkTriggerRule({ backSpace: true }) &&
(!prev || allowedLettersRegex.test(prev)) (!prev || allowedLettersRegex.test(prev))
) { ) {
completeStart = c; completeStart = c;
term = me[0].value.substring(c + 1, initial); term = me[0].value.substring(c + 1, initial);
if (!completeEnd) {
completeEnd = c + term.length;
}
updateAutoComplete(dataSource(term, options)); updateAutoComplete(dataSource(term, options));
return true; return true;
} }
@ -640,11 +656,12 @@ export default function (options) {
return false; return false;
case keys.backSpace: case keys.backSpace:
autocompleteOptions = null; autocompleteOptions = null;
completeEnd = cp;
cp--; cp--;
completeEnd = cp;
if (cp < 0) { if (cp < 0) {
closeAutocomplete(); closeAutocomplete();
if (isInput) { if (isInput) {
i = wrap.find("a:last"); i = wrap.find("a:last");
if (i) { if (i) {

View File

@ -0,0 +1,109 @@
import { test } from "qunit";
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
import { setCaretPosition } from "discourse/lib/utilities";
const BACKSPACE_KEYCODE = 8;
acceptance("Composer - editor mentions", function (needs) {
needs.user();
needs.settings({ enable_mentions: true });
needs.pretender((server, helper) => {
server.get("/u/search/users", () => {
return helper.response({
users: [
{
username: "user",
name: "Some User",
avatar_template:
"https://avatars.discourse.org/v3/letter/t/41988e/{size}.png",
},
{
username: "user2",
name: "Some User",
avatar_template:
"https://avatars.discourse.org/v3/letter/t/41988e/{size}.png",
},
],
});
});
});
test("selecting user mentions", async function (assert) {
await visit("/");
await click("#create-topic");
// Emulate user pressing backspace in the editor
const editor = query(".d-editor-input");
await triggerKeyEvent(".d-editor-input", "keydown", "@".charCodeAt(0));
await fillIn(".d-editor-input", "abc @");
await setCaretPosition(editor, 5);
await triggerKeyEvent(".d-editor-input", "keyup", "@".charCodeAt(0));
await triggerKeyEvent(".d-editor-input", "keydown", "u".charCodeAt(0));
await fillIn(".d-editor-input", "abc @u");
await setCaretPosition(editor, 6);
await triggerKeyEvent(".d-editor-input", "keyup", "u".charCodeAt(0));
await click(".autocomplete.ac-user .selected");
assert.strictEqual(
query(".d-editor-input").value,
"abc @user ",
"should replace mention correctly"
);
});
test("selecting user mentions after deleting characters", async function (assert) {
await visit("/");
await click("#create-topic");
await fillIn(".d-editor-input", "abc @user a");
// Emulate user typing `@` and `u` in the editor
await triggerKeyEvent(".d-editor-input", "keydown", BACKSPACE_KEYCODE);
await fillIn(".d-editor-input", "abc @user ");
await triggerKeyEvent(".d-editor-input", "keyup", BACKSPACE_KEYCODE);
await triggerKeyEvent(".d-editor-input", "keydown", BACKSPACE_KEYCODE);
await fillIn(".d-editor-input", "abc @user");
await triggerKeyEvent(".d-editor-input", "keyup", BACKSPACE_KEYCODE);
await click(".autocomplete.ac-user .selected");
assert.strictEqual(
query(".d-editor-input").value,
"abc @user ",
"should replace mention correctly"
);
});
test("selecting user mentions after deleting characters mid sentence", async function (assert) {
await visit("/");
await click("#create-topic");
// Emulate user pressing backspace in the editor
const editor = query(".d-editor-input");
await fillIn(".d-editor-input", "abc @user 123");
await setCaretPosition(editor, 9);
await triggerKeyEvent(".d-editor-input", "keydown", BACKSPACE_KEYCODE);
await fillIn(".d-editor-input", "abc @use 123");
await triggerKeyEvent(".d-editor-input", "keyup", BACKSPACE_KEYCODE);
await setCaretPosition(editor, 8);
await triggerKeyEvent(".d-editor-input", "keydown", BACKSPACE_KEYCODE);
await fillIn(".d-editor-input", "abc @us 123");
await triggerKeyEvent(".d-editor-input", "keyup", BACKSPACE_KEYCODE);
await setCaretPosition(editor, 7);
await click(".autocomplete.ac-user .selected");
assert.strictEqual(
query(".d-editor-input").value,
"abc @user 123",
"should replace mention correctly"
);
});
});