compose: Have at least 2 new lines before and after a quoted message.

Uptil now, 1 new line was added before and 1 after a quoted message. Now
for more breathing room around a quoted message, new lines are inserted
to space it from any content before and after by at least 2 new lines.

Fixes: #23608.
This commit is contained in:
N-Shar-ma
2023-01-30 16:35:09 +05:30
committed by Tim Abbott
parent 3feb536df3
commit 25d2e1caed
4 changed files with 135 additions and 41 deletions

View File

@@ -536,25 +536,17 @@ export function quote_and_reply(opts) {
const message = message_lists.current.selected_message();
const quoting_placeholder = $t({defaultMessage: "[Quoting…]"});
if (compose_state.has_message_content()) {
// The user already started typing a message,
// so we won't re-open the compose box.
if (!compose_state.has_message_content()) {
// The user has not started typing a message,
// so we will re-open the compose box.
// (If you did re-open the compose box, you
// are prone to glitches where you select the
// text, plus it's a complicated codepath that
// can have other unintended consequences.)
if ($textarea.caret() !== 0) {
// Insert a newline before quoted message if there is
// already some content in the compose box and quoted
// message is not being inserted at the beginning.
$textarea.caret("\n");
}
} else {
respond_to_message(opts);
}
compose_ui.insert_syntax_and_focus(quoting_placeholder + "\n", $textarea);
compose_ui.insert_syntax_and_focus(quoting_placeholder, $textarea, "block");
function replace_content(message) {
// Final message looks like:

View File

@@ -30,7 +30,7 @@ export function autosize_textarea($textarea) {
}
}
export function smart_insert($textarea, syntax) {
export function smart_insert_inline($textarea, syntax) {
function is_space(c) {
return c === " " || c === "\t" || c === "\n";
}
@@ -68,11 +68,69 @@ export function smart_insert($textarea, syntax) {
autosize_textarea($textarea);
}
export function insert_syntax_and_focus(syntax, $textarea = $("#compose-textarea")) {
export function smart_insert_block($textarea, syntax) {
const pos = $textarea.caret();
const before_str = $textarea.val().slice(0, pos);
const after_str = $textarea.val().slice(pos);
if (pos > 0) {
// Insert newline/s before the content block if there is
// already some content in the compose box and the content
// block is not being inserted at the beginning, such
// that there are at least 2 new lines between the content
// and start of the content block.
let new_lines_before_count = 0;
let current_pos = pos - 1;
while (
current_pos >= 0 &&
before_str.charAt(current_pos) === "\n" &&
new_lines_before_count < 2
) {
// count up to 2 new lines before cursor
current_pos -= 1;
new_lines_before_count += 1;
}
const new_lines_needed_before_count = 2 - new_lines_before_count;
syntax = "\n".repeat(new_lines_needed_before_count) + syntax;
}
let new_lines_after_count = 0;
let current_pos = 0;
while (
current_pos < after_str.length &&
after_str.charAt(current_pos) === "\n" &&
new_lines_after_count < 2
) {
// count up to 2 new lines after cursor
current_pos += 1;
new_lines_after_count += 1;
}
// Insert newline/s after the content block, such that there
// are at least 2 new lines between the content block and
// the content after the cursor, if any.
const new_lines_needed_after_count = 2 - new_lines_after_count;
syntax = syntax + "\n".repeat(new_lines_needed_after_count);
// text-field-edit ensures `$textarea` is focused before inserting
// the new syntax.
insert($textarea[0], syntax);
autosize_textarea($textarea);
}
export function insert_syntax_and_focus(
syntax,
$textarea = $("#compose-textarea"),
mode = "inline",
) {
// Generic helper for inserting syntax into the main compose box
// where the cursor was and focusing the area. Mostly a thin
// wrapper around smart_insert.
smart_insert($textarea, syntax);
// wrapper around smart_insert_inline and smart_inline_block.
if (mode === "inline") {
smart_insert_inline($textarea, syntax);
} else if (mode === "block") {
smart_insert_block($textarea, syntax);
}
}
export function replace_syntax(old_syntax, new_syntax, $textarea = $("#compose-textarea")) {

View File

@@ -359,8 +359,9 @@ test("quote_and_reply", ({disallow, override, override_rewire}) => {
override(message_lists.current, "selected_id", () => 100);
override(compose_ui, "insert_syntax_and_focus", (syntax) => {
assert.equal(syntax, "translated: [Quoting…]\n");
override(compose_ui, "insert_syntax_and_focus", (syntax, $textarea, mode) => {
assert.equal(syntax, "translated: [Quoting…]");
assert.equal(mode, "block");
});
const opts = {

View File

@@ -120,34 +120,34 @@ run_test("smart_insert", ({override}) => {
});
}
override_with_expected_syntax(" :smile: ");
compose_ui.smart_insert($textbox, ":smile:");
compose_ui.smart_insert_inline($textbox, ":smile:");
override_with_expected_syntax(" :airplane: ");
compose_ui.smart_insert($textbox, ":airplane:");
compose_ui.smart_insert_inline($textbox, ":airplane:");
$textbox.caret(0);
override_with_expected_syntax(":octopus: ");
compose_ui.smart_insert($textbox, ":octopus:");
compose_ui.smart_insert_inline($textbox, ":octopus:");
$textbox.caret($textbox.val().length);
override_with_expected_syntax(" :heart: ");
compose_ui.smart_insert($textbox, ":heart:");
compose_ui.smart_insert_inline($textbox, ":heart:");
// Test handling of spaces for ```quote
$textbox = make_textbox("");
$textbox.caret(0);
override_with_expected_syntax("```quote\nquoted message\n```\n");
compose_ui.smart_insert($textbox, "```quote\nquoted message\n```\n");
override_with_expected_syntax("```quote\nquoted message\n```\n\n");
compose_ui.smart_insert_block($textbox, "```quote\nquoted message\n```");
$textbox = make_textbox("");
$textbox.caret(0);
override_with_expected_syntax("translated: [Quoting…]\n");
compose_ui.smart_insert($textbox, "translated: [Quoting…]\n");
override_with_expected_syntax("translated: [Quoting…]\n\n");
compose_ui.smart_insert_block($textbox, "translated: [Quoting…]");
$textbox = make_textbox("abc");
$textbox.caret(3);
override_with_expected_syntax(" test with space ");
compose_ui.smart_insert($textbox, " test with space");
override_with_expected_syntax("\n\n test with space\n\n");
compose_ui.smart_insert_block($textbox, " test with space");
// Note that we don't have any special logic for strings that are
// already surrounded by spaces, since we are usually inserting things
@@ -281,23 +281,28 @@ run_test("quote_and_reply", ({override, override_rewire}) => {
textarea_caret_pos = arg;
return this;
}
/* istanbul ignore if */
if (typeof arg !== "string") {
console.info(arg);
throw new Error("We expected the actual code to pass in a string.");
/* This next block of mocking code is currently unused, but
is preserved, since it may be useful in the future. */
/* istanbul ignore next */
{
if (typeof arg !== "string") {
console.info(arg);
throw new Error("We expected the actual code to pass in a string.");
}
const before = textarea_val.slice(0, textarea_caret_pos);
const after = textarea_val.slice(textarea_caret_pos);
textarea_val = before + arg + after;
textarea_caret_pos += arg.length;
return this;
}
const before = textarea_val.slice(0, textarea_caret_pos);
const after = textarea_val.slice(textarea_caret_pos);
textarea_val = before + arg + after;
textarea_caret_pos += arg.length;
return this;
};
$("#compose-textarea")[0] = "compose-textarea";
override(text_field_edit, "insert", (elt, syntax) => {
assert.equal(elt, "compose-textarea");
assert.equal(syntax, "translated: [Quoting…]\n");
assert.equal(syntax, "\n\ntranslated: [Quoting…]\n\n");
});
function set_compose_content_with_caret(content) {
@@ -343,7 +348,11 @@ run_test("quote_and_reply", ({override, override_rewire}) => {
reset_test_state();
// If the caret is initially positioned at 0, it should not
// add a newline before the quoted message.
// add newlines before the quoted message.
override(text_field_edit, "insert", (elt, syntax) => {
assert.equal(elt, "compose-textarea");
assert.equal(syntax, "translated: [Quoting…]\n\n");
});
set_compose_content_with_caret("%hello there");
compose_actions.quote_and_reply();
@@ -387,6 +396,40 @@ run_test("quote_and_reply", ({override, override_rewire}) => {
success_function({
raw_content: quote_text,
});
reset_test_state();
// When there is already 1 newline before and after the caret,
// only 1 newline is added before and after the quoted message.
override(text_field_edit, "insert", (elt, syntax) => {
assert.equal(elt, "compose-textarea");
assert.equal(syntax, "\ntranslated: [Quoting…]\n");
});
set_compose_content_with_caret("1st line\n%\n2nd line");
compose_actions.quote_and_reply();
quote_text = "Testing with caret on a new line between 2 lines of text.";
override_with_quote_text(quote_text);
success_function({
raw_content: quote_text,
});
reset_test_state();
// When there are many (>=2) newlines before and after the caret,
// no newline is added before or after the quoted message.
override(text_field_edit, "insert", (elt, syntax) => {
assert.equal(elt, "compose-textarea");
assert.equal(syntax, "translated: [Quoting…]");
});
set_compose_content_with_caret("lots of\n\n\n\n%\n\n\nnewlines");
compose_actions.quote_and_reply();
quote_text = "Testing with caret on a new line between many empty newlines.";
override_with_quote_text(quote_text);
success_function({
raw_content: quote_text,
});
});
run_test("set_compose_box_top", () => {