mirror of
https://github.com/discourse/discourse.git
synced 2025-06-07 22:46:01 +08:00
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:
@ -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));
|
||||||
|
@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user