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';