From 4a1423b34a90ea6d9a983b36e3b2384c0ff0ec33 Mon Sep 17 00:00:00 2001 From: N-Shar-ma Date: Thu, 29 Feb 2024 21:01:01 +0530 Subject: [PATCH] copy_and_paste: Fix formatting of code pasted from VS Code. Since the html copied from VS Code is not structured as code but as styled divs for each line, any code copied from it would be pasted unformatted with blank lines between each line of code. This has now been fixed, by detecting VS Code style code blocks by the CSS property `white-space: pre` and pasting the text within as is, as code. --- web/src/copy_and_paste.js | 18 +++++++++++++++++- web/tests/copy_and_paste.test.js | 18 ++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/web/src/copy_and_paste.js b/web/src/copy_and_paste.js index 37d0965abd..ce186a5369 100644 --- a/web/src/copy_and_paste.js +++ b/web/src/copy_and_paste.js @@ -322,6 +322,16 @@ function within_single_element(html_fragment) { ); } +export function is_white_space_pre(paste_html) { + const html_fragment = new DOMParser() + .parseFromString(paste_html, "text/html") + .querySelector("body"); + return ( + within_single_element(html_fragment) && + html_fragment.firstElementChild.style.whiteSpace === "pre" + ); +} + export function paste_handler_converter(paste_html) { const copied_html_fragment = new DOMParser() .parseFromString(paste_html, "text/html") @@ -563,7 +573,7 @@ export function paste_handler(event) { if (clipboardData.getData) { const $textarea = $(event.currentTarget); const paste_text = clipboardData.getData("text"); - const paste_html = clipboardData.getData("text/html"); + let paste_html = clipboardData.getData("text/html"); // Trim the paste_text to accommodate sloppy copying const trimmed_paste_text = paste_text.trim(); @@ -589,6 +599,12 @@ export function paste_handler(event) { ) { event.preventDefault(); event.stopPropagation(); + if (is_white_space_pre(paste_html)) { + // Copied content styled with `white-space: pre` is pasted as is + // but formatted as code. We need this for content copied from + // VS Code like sources. + paste_html = "
" + paste_text + "
"; + } const text = paste_handler_converter(paste_html); compose_ui.insert_and_scroll_into_view(text, $textarea); } diff --git a/web/tests/copy_and_paste.test.js b/web/tests/copy_and_paste.test.js index 1e2185b308..340778adeb 100644 --- a/web/tests/copy_and_paste.test.js +++ b/web/tests/copy_and_paste.test.js @@ -8,6 +8,16 @@ const {page_params} = require("./lib/zpage_params"); const copy_and_paste = zrequire("copy_and_paste"); +run_test("is_white_space_pre", () => { + // Copied HTML from VS Code + let paste_html = `
if (message_lists.current === undefined) {
return;
}
`; + assert.ok(copy_and_paste.is_white_space_pre(paste_html)); + + // Negative test case + paste_html = "
Hello
World!
"; + assert.ok(!copy_and_paste.is_white_space_pre(paste_html)); +}); + run_test("paste_handler_converter", () => { page_params.development_environment = true; @@ -118,14 +128,6 @@ run_test("paste_handler_converter", () => { '
Test list:
'; assert.equal(copy_and_paste.paste_handler_converter(input), "Test list:\n* Item 1\n* Item 2"); - // Pasting code from VS Code / Gmail - input = - '
const compose_ui = mock_esm("../src/compose_ui");
set_global("document", document);
'; - assert.equal( - copy_and_paste.paste_handler_converter(input), - 'const compose_ui = mock_esm("../src/compose_ui");\n\nset_global("document", document);', - ); - // Pasting from Google Sheets (remove 123';