copy_and_paste: Don't add code syntax if backtick is already present.

This commit is contained in:
evykassirer
2024-12-06 16:32:17 -08:00
committed by Tim Abbott
parent 9ab6729d41
commit 10d7da81a0
2 changed files with 38 additions and 3 deletions

View File

@@ -435,7 +435,10 @@ export function is_single_image(paste_html: string): boolean {
);
}
export function paste_handler_converter(paste_html: string): string {
export function paste_handler_converter(
paste_html: string,
$textarea?: JQuery<HTMLTextAreaElement>,
): string {
const copied_html_fragment = new DOMParser()
.parseFromString(paste_html, "text/html")
.querySelector("body");
@@ -566,6 +569,9 @@ export function paste_handler_converter(paste_html: string): string {
// blocks too.
// - For Zulip code blocks, we extract the language of the code block (if
// any) correctly.
// - We don't do any conversion to code blocks if the user seems to already
// be trying to create a codeblock (i.e. the cursor in the composebox is
// following a "`").
// Everything else works the same.
turndownService.addRule("fencedCodeBlock", {
filter(node, options) {
@@ -580,7 +586,7 @@ export function paste_handler_converter(paste_html: string): string {
);
},
replacement(_content, node, options) {
replacement(content, node, options) {
assert(node instanceof HTMLElement);
const codeElement = [...node.children].find((child) => child.nodeName === "CODE");
assert(codeElement !== undefined);
@@ -590,6 +596,14 @@ export function paste_handler_converter(paste_html: string): string {
// We convert single line code inside a code block to inline markdown code,
// and the code for this is taken from upstream's `code` rule.
if (!code.includes("\n")) {
// If the cursor is just after a backtick, then we don't add extra backticks.
if (
$textarea &&
$textarea.caret() !== 0 &&
$textarea.val()?.at($textarea.caret() - 1) === "`"
) {
return content;
}
if (!code) {
return "";
}
@@ -808,7 +822,7 @@ export function paste_handler(this: HTMLTextAreaElement, event: JQuery.Triggered
event.preventDefault();
event.stopPropagation();
paste_html = maybe_transform_html(paste_html, paste_text);
const text = paste_handler_converter(paste_html);
const text = paste_handler_converter(paste_html, $textarea);
if (trimmed_paste_text !== text) {
// Pasting formatted text is a two-step process: First
// we paste unformatted text, then overwrite it with

View File

@@ -127,6 +127,27 @@ run_test("paste_handler_converter", () => {
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><pre><code>single line</code></pre>';
assert.equal(copy_and_paste.paste_handler_converter(input), "`single line`");
// No code formatting if the given text area has a backtick at the cursor position
input =
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><pre><code>single line</code></pre>';
assert.equal(
copy_and_paste.paste_handler_converter(input, {
caret: () => 6,
val: () => "e.g. `",
}),
"single line",
);
// Yes code formatting if the given text area has a backtick but not at the cursor position
input =
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><pre><code>single line</code></pre>';
assert.equal(
copy_and_paste.paste_handler_converter(input, {
caret: () => 0,
}),
"`single line`",
);
// Raw links without custom text
input =
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><a href="https://zulip.readthedocs.io/en/latest/subsystems/logging.html" target="_blank" title="https://zulip.readthedocs.io/en/latest/subsystems/logging.html" style="color: hsl(200, 100%, 40%); text-decoration: none; cursor: pointer; font-family: &quot;Source Sans 3&quot;, &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: hsl(0, 0%, 100%);">https://zulip.readthedocs.io/en/latest/subsystems/logging.html</a>';