insertLineBreak.html (7330B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <meta name="timeout" content="long"> 6 <meta name="variant" content="?white-space=normal"> 7 <meta name="variant" content="?white-space=pre"> 8 <meta name="variant" content="?white-space=pre-line"> 9 <meta name="variant" content="?white-space=pre-wrap"> 10 <title>Inserting a line break in plaintext-only</title> 11 <script src="/resources/testharness.js"></script> 12 <script src="/resources/testharnessreport.js"></script> 13 <script src="/resources/testdriver.js"></script> 14 <script src="/resources/testdriver-vendor.js"></script> 15 <script src="/resources/testdriver-actions.js"></script> 16 <script src="../include/editor-test-utils.js"></script> 17 <script> 18 "use strict"; 19 20 const searchParams = new URLSearchParams(document.location.search); 21 const whiteSpace = searchParams.get("white-space"); 22 const useBR = whiteSpace == "normal"; 23 const collapseWhiteSpaces = whiteSpace == "normal" || whiteSpace == "pre-line"; 24 const isSafari = navigator.platform.includes("Mac") && 25 navigator.userAgent.includes("Safari") && 26 !navigator.userAgent.includes("Chrome"); 27 28 addEventListener("load", () => { 29 const editingHost = document.createElement("div"); 30 editingHost.style.whiteSpace = whiteSpace; 31 editingHost.setAttribute("contenteditable", "plaintext-only"); 32 document.body.appendChild(editingHost); 33 editingHost.focus(); 34 editingHost.getBoundingClientRect(); 35 const utils = new EditorTestUtils(editingHost); 36 37 let lastBeforeInputEvent; 38 editingHost.addEventListener("beforeinput", event => lastBeforeInputEvent = event); 39 40 // When a preformatted linefeed is preferred, it should be used instead of <br> for making the 41 // content can be retrieved with `.textContent`. However, padding line breaks which is required 42 // for empty block or empty last line should be <br> because it won't appear in `.textContent`. 43 // So, it helps to make the `.textContent` result better. 44 for (const data of [ 45 { 46 initialInnerHTML: "A[]B", 47 expected: useBR ? "A<br>B" : "A\nB", 48 }, 49 { 50 initialInnerHTML: "<p>{}<br></p>", 51 expected: useBR ? "<p><br><br></p>" : "<p>\n<br></p>", 52 }, 53 { 54 initialInnerHTML: `<p style="white-space:normal">A[]B</p>`, 55 expected: `<p style="white-space:normal">A<br>B</p>`, 56 }, 57 { 58 initialInnerHTML: `<p style="white-space:pre">A[]B</p>`, 59 expected: [`<p style="white-space:pre">A<br>B</p>`, `<p style="white-space:pre">A\nB</p>`], 60 }, 61 { 62 initialInnerHTML: `<p style="white-space:pre-line">A[]B</p>`, 63 expected: [`<p style="white-space:pre-line">A<br>B</p>`, `<p style="white-space:pre-line">A\nB</p>`], 64 }, 65 { 66 initialInnerHTML: `<p style="white-space:pre-wrap">A[]B</p>`, 67 expected: [`<p style="white-space:pre-wrap">A<br>B</p>`, `<p style="white-space:pre-wrap">A\nB</p>`], 68 }, 69 { 70 initialInnerHTML: "<ul><li>[]AB</li></ul>", 71 expected: useBR ? "<ul><li><br>AB</li></ul>" : "<ul><li>\nAB</li></ul>", 72 }, 73 { 74 initialInnerHTML: "<ul><li>A[]B</li></ul>", 75 expected: useBR ? "<ul><li>A<br>B</li></ul>" : "<ul><li>A\nB</li></ul>", 76 }, 77 { 78 initialInnerHTML: "<ul><li>AB[]</li></ul>", 79 expected: useBR 80 ? "<ul><li>AB<br><br></li></ul>" 81 : "<ul><li>AB\n<br></li></ul>", 82 }, 83 { 84 initialInnerHTML: "<dl><dt>[]AB</dt></dl>", 85 expected: useBR ? "<dl><dt><br>AB</dt></dl>" : "<dl><dt>\nAB</dt></dl>", 86 }, 87 { 88 initialInnerHTML: "<dl><dt>A[]B</dt></dl>", 89 expected: useBR ? "<dl><dt>A<br>B</dt></dl>" : "<dl><dt>A\nB</dt></dl>", 90 }, 91 { 92 initialInnerHTML: "<dl><dt>AB[]</dt></dl>", 93 expected: useBR 94 ? "<dl><dt>AB<br><br></dt></dl>" 95 : "<dl><dt>AB\n<br></dt></dl>", 96 }, 97 { 98 initialInnerHTML: "<dl><dd>[]AB</dd></dl>", 99 expected: useBR ? "<dl><dd><br>AB</dd></dl>" : "<dl><dd>\nAB</dd></dl>", 100 }, 101 { 102 initialInnerHTML: "<dl><dd>A[]B</dd></dl>", 103 expected: useBR ? "<dl><dd>A<br>B</dd></dl>" : "<dl><dd>A\nB</dd></dl>", 104 }, 105 { 106 initialInnerHTML: "<dl><dd>AB[]</dd></dl>", 107 expected: useBR 108 ? "<dl><dd>AB<br><br></dd></dl>" 109 : "<dl><dd>AB\n<br></dd></dl>", 110 }, 111 { 112 initialInnerHTML: "<table><tbody><tr><td>[]AB</td></tr></tbody></table>", 113 expected: useBR 114 ? "<table><tbody><tr><td><br>AB</td></tr></tbody></table>" 115 : "<table><tbody><tr><td>\nAB</td></tr></tbody></table>", 116 }, 117 { 118 initialInnerHTML: "<table><tbody><tr><td>A[]B</td></tr></tbody></table>", 119 expected: useBR 120 ? "<table><tbody><tr><td>A<br>B</td></tr></tbody></table>" 121 : "<table><tbody><tr><td>A\nB</td></tr></tbody></table>", 122 }, 123 { 124 initialInnerHTML: "<table><tbody><tr><td>AB[]</td></tr></tbody></table>", 125 expected: useBR 126 ? "<table><tbody><tr><td>AB<br><br></td></tr></tbody></table>" 127 : "<table><tbody><tr><td>AB\n<br></td></tr></tbody></table>", 128 }, 129 { 130 initialInnerHTML: "<h1>[]AB</h1>", 131 expected: useBR ? "<h1><br>AB</h1>" : "<h1>\nAB</h1>", 132 }, 133 { 134 initialInnerHTML: "<h1>A[]B</h1>", 135 expected: useBR ? "<h1>A<br>B</h1>" : "<h1>A\nB</h1>", 136 }, 137 { 138 initialInnerHTML: "<h1>AB[]</h1>", 139 expected: useBR ? "<h1>AB<br><br></h1>" : "<h1>AB\n<br></h1>", 140 }, 141 ]) { 142 test(() => { 143 utils.setupEditingHost(data.initialInnerHTML); 144 document.execCommand("insertLineBreak"); 145 if (Array.isArray(data.expected)) { 146 assert_in_array(editingHost.innerHTML, data.expected); 147 } else { 148 assert_equals(editingHost.innerHTML, data.expected); 149 } 150 }, `execCommand("insertLineBreak") when ${data.initialInnerHTML}`); 151 promise_test(async t => { 152 utils.setupEditingHost(data.initialInnerHTML); 153 lastBeforeInputEvent = undefined; 154 await utils.sendEnterKey(); 155 test(() => { 156 assert_equals( 157 lastBeforeInputEvent?.inputType, 158 "insertLineBreak", 159 `inputType should be "insertLineBreak"` 160 ); 161 }, `${t.name}: beforeinput`); 162 test(() => { 163 if (Array.isArray(data.expected)) { 164 assert_in_array(editingHost.innerHTML, data.expected); 165 } else { 166 assert_equals(editingHost.innerHTML, data.expected); 167 } 168 }, `${t.name}: editingHost.innerHTML`); 169 }, `Pressing Enter when ${ 170 data.initialInnerHTML 171 } should cause "insertLineBreak" and shouldn't insert new paragraph`); 172 promise_test(async t => { 173 utils.setupEditingHost(data.initialInnerHTML); 174 lastBeforeInputEvent = undefined; 175 await utils.sendEnterKey(isSafari ? utils.kControl : utils.kShift); 176 test(() => { 177 assert_equals( 178 lastBeforeInputEvent?.inputType, 179 "insertLineBreak", 180 `inputType should be "insertLineBreak"` 181 ); 182 }, `${t.name}: beforeinput`); 183 test(() => { 184 if (Array.isArray(data.expected)) { 185 assert_in_array(editingHost.innerHTML, data.expected); 186 } else { 187 assert_equals(editingHost.innerHTML, data.expected); 188 } 189 }, `${t.name}: editingHost.innerHTML`); 190 }, `Pressing ${isSafari ? "Ctrl" : "Shift"}+Enter when ${ 191 data.initialInnerHTML 192 } should cause "insertLineBreak" and shouldn't insert new paragraph`); 193 } 194 }, {once: true}); 195 </script> 196 </head> 197 <body></body> 198 </html>