mirror of https://github.com/zulip/zulip.git
compose: Trigger language typeahead on using code formatting button.
To increase the discoverability of the possibility of specifying the language for a code block, we trigger the language typeahead when code syntax is added using the code formatting button. A blank option is shown preselected in the typeahead, so that pressing enter will not mistakenly add a language to the code block. We only trigger the typeahead on empty opening fences when added by the button, by setting a state variable to true when adding the syntax using the button, checking for this state when sourcing languages for the code typeahead, and then resetting the state variable to false. Fixes: #29150.
This commit is contained in:
parent
4f051d653c
commit
9cedf0e8bc
|
@ -46,8 +46,13 @@ type SelectedLinesSections = {
|
||||||
|
|
||||||
export let compose_spinner_visible = false;
|
export let compose_spinner_visible = false;
|
||||||
export let shift_pressed = false; // true or false
|
export let shift_pressed = false; // true or false
|
||||||
|
export let code_formatting_button_triggered = false; // true or false
|
||||||
let full_size_status = false; // true or false
|
let full_size_status = false; // true or false
|
||||||
|
|
||||||
|
export function set_code_formatting_button_triggered(value: boolean): void {
|
||||||
|
code_formatting_button_triggered = value;
|
||||||
|
}
|
||||||
|
|
||||||
// Some functions to handle the full size status explicitly
|
// Some functions to handle the full size status explicitly
|
||||||
export function set_full_size(is_full: boolean): void {
|
export function set_full_size(is_full: boolean): void {
|
||||||
full_size_status = is_full;
|
full_size_status = is_full;
|
||||||
|
@ -1011,7 +1016,15 @@ export function format_text(
|
||||||
if (range.end < text.length && text[range.end] !== "\n") {
|
if (range.end < text.length && text[range.end] !== "\n") {
|
||||||
block_code_syntax_end = block_code_syntax_end + "\n";
|
block_code_syntax_end = block_code_syntax_end + "\n";
|
||||||
}
|
}
|
||||||
format(block_code_syntax_start, block_code_syntax_end);
|
const added_fence = format(block_code_syntax_start, block_code_syntax_end);
|
||||||
|
if (added_fence) {
|
||||||
|
const cursor_after_opening_fence =
|
||||||
|
range.start + block_code_syntax_start.length - 1;
|
||||||
|
field.setSelectionRange(cursor_after_opening_fence, cursor_after_opening_fence);
|
||||||
|
set_code_formatting_button_triggered(true);
|
||||||
|
// Trigger typeahead lookup with a click.
|
||||||
|
field.click();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
format(inline_code_syntax);
|
format(inline_code_syntax);
|
||||||
}
|
}
|
||||||
|
|
|
@ -689,13 +689,15 @@ export function get_candidates(query) {
|
||||||
const syntax_token = current_token.slice(0, 3);
|
const syntax_token = current_token.slice(0, 3);
|
||||||
if (ALLOWED_MARKDOWN_FEATURES.syntax && (syntax_token === "```" || syntax_token === "~~~")) {
|
if (ALLOWED_MARKDOWN_FEATURES.syntax && (syntax_token === "```" || syntax_token === "~~~")) {
|
||||||
// Only autocomplete if user starts typing a language after ```
|
// Only autocomplete if user starts typing a language after ```
|
||||||
if (current_token.length === 3) {
|
// unless the fence was added via the code formatting button.
|
||||||
|
if (current_token.length === 3 && !compose_ui.code_formatting_button_triggered) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the only input is a space, don't autocomplete
|
// If the only input is a space, don't autocomplete
|
||||||
current_token = current_token.slice(3);
|
current_token = current_token.slice(3);
|
||||||
if (current_token === " ") {
|
if (current_token === " ") {
|
||||||
|
compose_ui.set_code_formatting_button_triggered(false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +707,13 @@ export function get_candidates(query) {
|
||||||
}
|
}
|
||||||
this.completing = "syntax";
|
this.completing = "syntax";
|
||||||
this.token = current_token;
|
this.token = current_token;
|
||||||
return realm_playground.get_pygments_typeahead_list_for_composebox();
|
// If the code formatting button was triggered, we want to show a blank option
|
||||||
|
// to improve the discoverability of the possibility of specifying a language.
|
||||||
|
const language_list = compose_ui.code_formatting_button_triggered
|
||||||
|
? ["", ...realm_playground.get_pygments_typeahead_list_for_composebox()]
|
||||||
|
: realm_playground.get_pygments_typeahead_list_for_composebox();
|
||||||
|
compose_ui.set_code_formatting_button_triggered(false);
|
||||||
|
return language_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only start the emoji autocompleter if : is directly after one
|
// Only start the emoji autocompleter if : is directly after one
|
||||||
|
|
|
@ -795,6 +795,14 @@ strong {
|
||||||
color: hsl(0deg 0% 20%);
|
color: hsl(0deg 0% 20%);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
/* hidden text just to maintain line height for a blank option */
|
||||||
|
strong:empty {
|
||||||
|
&::after {
|
||||||
|
content: ".";
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,6 +509,7 @@ $textarea.get = () => ({
|
||||||
length: end - start,
|
length: end - start,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
click() {},
|
||||||
});
|
});
|
||||||
|
|
||||||
// The argument `text_representation` is a string representing the text
|
// The argument `text_representation` is a string representing the text
|
||||||
|
@ -860,17 +861,17 @@ run_test("format_text - code", ({override, override_rewire}) => {
|
||||||
compose_ui.format_text($textarea, "code");
|
compose_ui.format_text($textarea, "code");
|
||||||
assert.equal(
|
assert.equal(
|
||||||
get_textarea_state(),
|
get_textarea_state(),
|
||||||
"Before\nBefore \n```\n<this should\nbe code>\n```\n After\nAfter",
|
"Before\nBefore \n```|\nthis should\nbe code\n```\n After\nAfter",
|
||||||
);
|
);
|
||||||
|
|
||||||
init_textarea_state("<abc\ndef>");
|
init_textarea_state("<abc\ndef>");
|
||||||
compose_ui.format_text($textarea, "code");
|
compose_ui.format_text($textarea, "code");
|
||||||
assert.equal(get_textarea_state(), "```\n<abc\ndef>\n```");
|
assert.equal(get_textarea_state(), "```|\nabc\ndef\n```");
|
||||||
|
|
||||||
// Code, no selection
|
// Code, no selection
|
||||||
init_textarea_state("|");
|
init_textarea_state("|");
|
||||||
compose_ui.format_text($textarea, "code");
|
compose_ui.format_text($textarea, "code");
|
||||||
assert.equal(get_textarea_state(), "```\n|\n```");
|
assert.equal(get_textarea_state(), "```|\n\n```");
|
||||||
|
|
||||||
// Undo code selected text, syntax not selected
|
// Undo code selected text, syntax not selected
|
||||||
init_textarea_state("before `<abc>` after");
|
init_textarea_state("before `<abc>` after");
|
||||||
|
|
|
@ -16,6 +16,7 @@ const compose_ui = mock_esm("../src/compose_ui", {
|
||||||
autosize_called = true;
|
autosize_called = true;
|
||||||
},
|
},
|
||||||
cursor_inside_code_block: () => false,
|
cursor_inside_code_block: () => false,
|
||||||
|
set_code_formatting_button_triggered: noop,
|
||||||
});
|
});
|
||||||
const compose_validate = mock_esm("../src/compose_validate", {
|
const compose_validate = mock_esm("../src/compose_validate", {
|
||||||
validate_message_length: () => true,
|
validate_message_length: () => true,
|
||||||
|
|
Loading…
Reference in New Issue