mirror of https://github.com/zulip/zulip.git
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.
This commit is contained in:
parent
c440b4575e
commit
4a1423b34a
|
@ -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) {
|
export function paste_handler_converter(paste_html) {
|
||||||
const copied_html_fragment = new DOMParser()
|
const copied_html_fragment = new DOMParser()
|
||||||
.parseFromString(paste_html, "text/html")
|
.parseFromString(paste_html, "text/html")
|
||||||
|
@ -563,7 +573,7 @@ export function paste_handler(event) {
|
||||||
if (clipboardData.getData) {
|
if (clipboardData.getData) {
|
||||||
const $textarea = $(event.currentTarget);
|
const $textarea = $(event.currentTarget);
|
||||||
const paste_text = clipboardData.getData("text");
|
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
|
// Trim the paste_text to accommodate sloppy copying
|
||||||
const trimmed_paste_text = paste_text.trim();
|
const trimmed_paste_text = paste_text.trim();
|
||||||
|
|
||||||
|
@ -589,6 +599,12 @@ export function paste_handler(event) {
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
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 = "<pre><code>" + paste_text + "</code></pre>";
|
||||||
|
}
|
||||||
const text = paste_handler_converter(paste_html);
|
const text = paste_handler_converter(paste_html);
|
||||||
compose_ui.insert_and_scroll_into_view(text, $textarea);
|
compose_ui.insert_and_scroll_into_view(text, $textarea);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,16 @@ const {page_params} = require("./lib/zpage_params");
|
||||||
|
|
||||||
const copy_and_paste = zrequire("copy_and_paste");
|
const copy_and_paste = zrequire("copy_and_paste");
|
||||||
|
|
||||||
|
run_test("is_white_space_pre", () => {
|
||||||
|
// Copied HTML from VS Code
|
||||||
|
let paste_html = `<div style="color: #cccccc;background-color: #1f1f1f;font-family: 'Droid Sans Mono', 'monospace', monospace;font-weight: normal;font-size: 14px;line-height: 19px;white-space: pre;"><div><span style="color: #cccccc;"> </span><span style="color: #c586c0;">if</span><span style="color: #cccccc;"> (</span><span style="color: #9cdcfe;">message_lists</span><span style="color: #cccccc;">.</span><span style="color: #9cdcfe;">current</span><span style="color: #cccccc;"> </span><span style="color: #d4d4d4;">===</span><span style="color: #cccccc;"> </span><span style="color: #569cd6;">undefined</span><span style="color: #cccccc;">) {</span></div><div><span style="color: #cccccc;"> </span><span style="color: #c586c0;">return</span><span style="color: #cccccc;">;</span></div><div><span style="color: #cccccc;"> }</span></div></div>`;
|
||||||
|
assert.ok(copy_and_paste.is_white_space_pre(paste_html));
|
||||||
|
|
||||||
|
// Negative test case
|
||||||
|
paste_html = "<div><div>Hello</div><div>World!</div></div>";
|
||||||
|
assert.ok(!copy_and_paste.is_white_space_pre(paste_html));
|
||||||
|
});
|
||||||
|
|
||||||
run_test("paste_handler_converter", () => {
|
run_test("paste_handler_converter", () => {
|
||||||
page_params.development_environment = true;
|
page_params.development_environment = true;
|
||||||
|
|
||||||
|
@ -118,14 +128,6 @@ run_test("paste_handler_converter", () => {
|
||||||
'<div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z ace-ltr focused-line" dir="auto" id="editor-3-ace-line-41"><span>Test list:</span></div><div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z line-list-type-bullet ace-ltr" dir="auto" id="editor-3-ace-line-42"><ul class="listtype-bullet listindent1 list-bullet1"><li><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="end"></span><span class="ace-line-pocket" data-faketext="" contenteditable="false"></span><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="start"></span><span>Item 1</span></li></ul></div><div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z line-list-type-bullet ace-ltr" dir="auto" id="editor-3-ace-line-43"><ul class="listtype-bullet listindent1 list-bullet1"><li><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="end"></span><span class="ace-line-pocket" data-faketext="" contenteditable="false"></span><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="start"></span><span>Item 2</span></li></ul></div>';
|
'<div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z ace-ltr focused-line" dir="auto" id="editor-3-ace-line-41"><span>Test list:</span></div><div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z line-list-type-bullet ace-ltr" dir="auto" id="editor-3-ace-line-42"><ul class="listtype-bullet listindent1 list-bullet1"><li><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="end"></span><span class="ace-line-pocket" data-faketext="" contenteditable="false"></span><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="start"></span><span>Item 1</span></li></ul></div><div class="ace-line gutter-author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90za3z66zs0z65zz65zq8z75zlaz81zcz66zj6g2mz78zz76zmz66z22z75zfcz69zz66z line-list-type-bullet ace-ltr" dir="auto" id="editor-3-ace-line-43"><ul class="listtype-bullet listindent1 list-bullet1"><li><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="end"></span><span class="ace-line-pocket" data-faketext="" contenteditable="false"></span><span class="ace-line-pocket-zws" data-faketext="" data-contentcollector-ignore-space-at="start"></span><span>Item 2</span></li></ul></div>';
|
||||||
assert.equal(copy_and_paste.paste_handler_converter(input), "Test list:\n* Item 1\n* Item 2");
|
assert.equal(copy_and_paste.paste_handler_converter(input), "Test list:\n* Item 1\n* Item 2");
|
||||||
|
|
||||||
// Pasting code from VS Code / Gmail
|
|
||||||
input =
|
|
||||||
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><div style="color: #ffffff;background-color: #002451;font-family: Consolas, "Courier New", monospace;font-weight: normal;font-size: 14px;line-height: 19px;white-space: pre;"><div><span style="color: #ebbbff;">const</span><span style="color: #ffffff;"> </span><span style="color: #ff9da4;">compose_ui</span><span style="color: #ffffff;"> </span><span style="color: #99ffff;">=</span><span style="color: #ffffff;"> </span><span style="color: #bbdaff;">mock_esm</span><span style="color: #ffffff;">(</span><span style="color: #d1f1a9;">"../src/compose_ui"</span><span style="color: #ffffff;">);</span></div><div><span style="color: #bbdaff;">set_global</span><span style="color: #ffffff;">(</span><span style="color: #d1f1a9;">"document"</span><span style="color: #ffffff;">, </span><span style="color: #ff9da4;">document</span><span style="color: #ffffff;">);</span></div></div>';
|
|
||||||
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 <style> elements completely)
|
// Pasting from Google Sheets (remove <style> elements completely)
|
||||||
input =
|
input =
|
||||||
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><style type="text/css"><!--td {border: 1px solid #cccccc;}br {mso-data-placement:same-cell;}--></style><span style="font-size:10pt;font-family:Arial;font-style:normal;text-align:right;" data-sheets-value="{"1":3,"3":123}" data-sheets-userformat="{"2":769,"3":{"1":0},"11":3,"12":0}">123</span>';
|
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><style type="text/css"><!--td {border: 1px solid #cccccc;}br {mso-data-placement:same-cell;}--></style><span style="font-size:10pt;font-family:Arial;font-style:normal;text-align:right;" data-sheets-value="{"1":3,"3":123}" data-sheets-userformat="{"2":769,"3":{"1":0},"11":3,"12":0}">123</span>';
|
||||||
|
|
Loading…
Reference in New Issue