diff --git a/web/src/compose_ui.js b/web/src/compose_ui.js index eebb209ac8..d4d03b1358 100644 --- a/web/src/compose_ui.js +++ b/web/src/compose_ui.js @@ -702,6 +702,30 @@ export function format_text($textarea, type, inserted_content) { $textarea.caret(range.end + `[](${inserted_content})`.length); break; } + case "latex": { + const inline_latex_syntax = "$$"; + let block_latex_syntax_start = "```math\n"; + let block_latex_syntax_end = "\n```"; + // If there is no text selected or the selected text is either multiline or + // already using multiline math syntax, we use multiline math syntax. + if ( + selected_text === "" || + selected_text.includes("\n") || + is_selection_formatted(block_latex_syntax_start, block_latex_syntax_end) + ) { + // Add newlines before and after, if not already present. + if (range.start > 0 && text[range.start - 1] !== "\n") { + block_latex_syntax_start = "\n" + block_latex_syntax_start; + } + if (range.end < text.length && text[range.end] !== "\n") { + block_latex_syntax_end = block_latex_syntax_end + "\n"; + } + format(block_latex_syntax_start, block_latex_syntax_end); + } else { + format(inline_latex_syntax); + } + break; + } } } diff --git a/web/templates/popovers/compose_control_buttons/compose_control_buttons_in_popover.hbs b/web/templates/popovers/compose_control_buttons/compose_control_buttons_in_popover.hbs index d6ad0562e0..cfc35d7729 100644 --- a/web/templates/popovers/compose_control_buttons/compose_control_buttons_in_popover.hbs +++ b/web/templates/popovers/compose_control_buttons/compose_control_buttons_in_popover.hbs @@ -7,5 +7,7 @@
|
+ +
|
diff --git a/web/tests/compose_ui.test.js b/web/tests/compose_ui.test.js index 3caeae99e0..24af865775 100644 --- a/web/tests/compose_ui.test.js +++ b/web/tests/compose_ui.test.js @@ -810,6 +810,141 @@ run_test("format_text - strikethrough", ({override}) => { assert.equal(set_text, "abc"); }); +run_test("format_text - latex", ({override}) => { + override(text_field_edit, "set", (_field, text) => { + set_text = text; + }); + override(text_field_edit, "wrapSelection", (_field, syntax_start, syntax_end) => { + wrap_selection_called = true; + wrap_syntax_start = syntax_start; + wrap_syntax_end = syntax_end; + }); + + const latex_syntax = "$$"; + const block_latex_syntax_start = "```math\n"; + const block_latex_syntax_end = "\n```"; + + // Latex selected text + reset_state(); + init_textarea("abc", { + start: 0, + end: 3, + text: "abc", + length: 3, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, ""); + assert.equal(wrap_selection_called, true); + assert.equal(wrap_syntax_start, latex_syntax); + assert.equal(wrap_syntax_end, latex_syntax); + + reset_state(); + init_textarea("Before\nBefore this should\nbe math After\nAfter", { + start: 14, + end: 33, + text: "this should\nbe math", + length: 19, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, ""); + assert.equal(wrap_selection_called, true); + assert.equal(wrap_syntax_start, "\n" + block_latex_syntax_start); + assert.equal(wrap_syntax_end, block_latex_syntax_end + "\n"); + + reset_state(); + init_textarea("abc\ndef", { + start: 0, + end: 7, + text: "abc\ndef", + length: 7, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, ""); + assert.equal(wrap_selection_called, true); + assert.equal(wrap_syntax_start, block_latex_syntax_start); + assert.equal(wrap_syntax_end, block_latex_syntax_end); + + // No text selected + reset_state(); + init_textarea("", { + start: 0, + end: 0, + text: "", + length: 0, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, ""); + assert.equal(wrap_selection_called, true); + + // Undo latex selected text, syntax not selected + reset_state(); + init_textarea("$$abc$$", { + start: 2, + end: 5, + text: "abc", + length: 3, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc"); + assert.equal(wrap_selection_called, false); + + reset_state(); + init_textarea("```math\nabc\ndef\n```", { + start: 8, + end: 15, + text: "abc\ndef", + length: 7, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc\ndef"); + assert.equal(wrap_selection_called, false); + + reset_state(); + init_textarea("abc\n```math\nde\nf\n```\nghi", { + start: 12, + end: 16, + text: "de\nf", + length: 4, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc\nde\nf\nghi"); + assert.equal(wrap_selection_called, false); + + // Undo latex selected text, syntax selected + reset_state(); + init_textarea("$$abc$$", { + start: 0, + end: 7, + text: "$$abc$$", + length: 7, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc"); + assert.equal(wrap_selection_called, false); + + reset_state(); + init_textarea("```math\nabc\ndef\n```", { + start: 0, + end: 19, + text: "```math\nabc\ndef\n```", + length: 19, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc\ndef"); + assert.equal(wrap_selection_called, false); + + reset_state(); + init_textarea("abc\n```math\nde\nf\n```\nghi", { + start: 4, + end: 20, + text: "```math\nde\nf\n```", + length: 16, + }); + compose_ui.format_text($textarea, "latex"); + assert.equal(set_text, "abc\nde\nf\nghi"); + assert.equal(wrap_selection_called, false); +}); + run_test("markdown_shortcuts", ({override_rewire}) => { let format_text_type; override_rewire(compose_ui, "format_text", (_$textarea, type) => {