UX: re-check triggerRule to avoid autocomplete in code (#30961)

Re-checks triggerRule when navigating around with arrow keys and after
continued typing.

ref /t/-/23884
This commit is contained in:
Renato Atilio
2025-01-27 18:55:24 -03:00
committed by GitHub
parent a5f533667d
commit 7206a7182b
3 changed files with 49 additions and 24 deletions

View File

@ -555,7 +555,7 @@ export default function (options) {
if (options.onKeyUp && key !== options.key) { if (options.onKeyUp && key !== options.key) {
let match = options.onKeyUp(options.textHandler.value, cp); let match = options.onKeyUp(options.textHandler.value, cp);
if (match) { if (match && (await checkTriggerRule())) {
completeStart = cp - match[0].length; completeStart = cp - match[0].length;
let term = match[0].substring(1, match[0].length); let term = match[0].substring(1, match[0].length);
updateAutoComplete(dataSource(term, options)); updateAutoComplete(dataSource(term, options));
@ -567,8 +567,8 @@ export default function (options) {
if (key === options.key) { if (key === options.key) {
let prevChar = options.textHandler.value.charAt(cp - 2); let prevChar = options.textHandler.value.charAt(cp - 2);
if ( if (
(await checkTriggerRule()) && (!prevChar || ALLOWED_LETTERS_REGEXP.test(prevChar)) &&
(!prevChar || ALLOWED_LETTERS_REGEXP.test(prevChar)) (await checkTriggerRule())
) { ) {
completeStart = cp - 1; completeStart = cp - 1;
updateAutoComplete(dataSource("", options)); updateAutoComplete(dataSource("", options));

View File

@ -737,10 +737,7 @@ export default class TextareaTextManipulation {
} }
async inCodeBlock() { async inCodeBlock() {
return inCodeBlock( return await this.autocompleteHandler.inCodeBlock();
this.$textarea.value ?? this.$textarea.val(),
caretPosition(this.$textarea)
);
} }
@bind @bind
@ -869,9 +866,9 @@ export class TextareaAutocompleteHandler {
} }
async inCodeBlock() { async inCodeBlock() {
return inCodeBlock( return await inCodeBlock(
this.$textarea.value ?? this.$textarea.val(), this.textarea.value ?? this.$textarea.val(),
caretPosition(this.$textarea) caretPosition(this.textarea)
); );
} }
} }

View File

@ -185,10 +185,19 @@ module("Unit | Utility | autocomplete", function (hooks) {
assert.dom(element).hasValue(":smile: "); assert.dom(element).hasValue(":smile: ");
await triggerArrowKey(element, "ArrowLeft"); async function triggerArrowKey(key) {
await triggerArrowKey(element, "ArrowLeft"); await triggerKeyEvent(element, "keydown", key, { code: key });
await triggerArrowKey(element, "ArrowLeft"); await triggerKeyEvent(element, "keyup", key, { code: key });
await triggerArrowKey(element, "ArrowRight");
const pos = element.selectionStart;
const direction = key === "ArrowLeft" ? -1 : 1;
element.setSelectionRange(pos + 1 * direction, pos + 1 * direction);
}
await triggerArrowKey("ArrowLeft");
await triggerArrowKey("ArrowLeft");
await triggerArrowKey("ArrowLeft");
await triggerArrowKey("ArrowRight");
assert.strictEqual(element.selectionStart, 6); assert.strictEqual(element.selectionStart, 6);
@ -196,19 +205,38 @@ module("Unit | Utility | autocomplete", function (hooks) {
// triggerArrowKey isn't triggering the event the autocomplete listens to // triggerArrowKey isn't triggering the event the autocomplete listens to
assert.dom("#ac-testing").doesNotExist(); assert.dom("#ac-testing").doesNotExist();
await triggerArrowKey(element, "ArrowRight"); await triggerArrowKey("ArrowRight");
await simulateKey(element, "\b"); await simulateKey(element, "\b");
assert.dom(element).hasValue(":smile "); assert.dom(element).hasValue(":smile ");
assert.dom("#ac-testing").exists(); assert.dom("#ac-testing").exists();
}); });
test("Autocomplete respects triggerRule on continued typing", async function (assert) {
const element = textArea();
$(element).autocomplete({
key: ":",
template,
transformComplete: (e) => e.slice(1),
dataSource: () => [":smile:"],
triggerRule: async (_, { inCodeBlock }) => !(await inCodeBlock()),
});
await simulateKeys(element, "```\n:");
assert.dom("#ac-testing").doesNotExist();
await simulateKey(element, "smil");
assert.dom("#ac-testing").doesNotExist();
await simulateKey(element, "\n```\n:");
assert.dom("#ac-testing").exists();
await simulateKey(element, "smil");
assert.dom("#ac-testing").exists();
});
}); });
async function triggerArrowKey(element, key) {
await triggerKeyEvent(element, "keydown", key, { code: key });
await triggerKeyEvent(element, "keyup", key, { code: key });
const pos = element.selectionStart;
const direction = key === "ArrowLeft" ? -1 : 1;
element.setSelectionRange(pos + 1 * direction, pos + 1 * direction);
}