insert-text-in-void-element.tentative.html (10742B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>Test insertText when selection collapsed in void element</title> 4 <meta name="timeout" content="long"> 5 <script src=/resources/testharness.js></script> 6 <script src=/resources/testharnessreport.js></script> 7 <div contenteditable></div> 8 <script> 9 "use strict"; 10 11 const voidElements = [ 12 "br", 13 "embed", 14 "hr", 15 "img", 16 "input", 17 "wbr", 18 ]; 19 20 // This test tests whether the inserted text is inserted into, when selection 21 // is collapsed in the void element. The expected results are based on Blink, 22 // but the results of <embed> and <wbr> elements are not consistent with the 23 // other elements'. Therefore, Blink also does not pass some of the following 24 // tests. 25 // FYI: This cannot be tested by editing/run because there is no way to collapse 26 // selection into a void element with the framework. 27 28 const editor = document.querySelector("div[contenteditable]"); 29 for (const tag of voidElements) { 30 test(() => { 31 editor.innerHTML = `<div></div>`; 32 const element = document.createElement(tag); 33 editor.firstChild.appendChild(element); 34 editor.focus(); 35 const selection = getSelection(); 36 selection.collapse(element, 0); 37 document.execCommand("insertText", false, "abc"); 38 if (tag == "br") { 39 assert_in_array( 40 editor.innerHTML, 41 [ 42 "<div>abc</div>", 43 "<div>abc<br></div>", 44 ], 45 `The text should be inserted before the <br> element` 46 ); 47 } else { 48 assert_in_array( 49 editor.innerHTML, 50 [ 51 `<div>abc<${tag}></div>`, 52 `<div>abc<${tag}><br></div>`, 53 ], 54 `The text should be inserted before the <${tag}> element` 55 ); 56 } 57 }, `Inserting text when selection is collapsed in <${tag}> which is only child`); 58 59 test(() => { 60 editor.innerHTML = `<div></div>`; 61 const element = document.createElement(tag); 62 editor.firstChild.appendChild(element); 63 editor.focus(); 64 const selection = getSelection(); 65 selection.collapse(element, 0); 66 element.getBoundingClientRect(); 67 document.execCommand("insertText", false, "abc"); 68 if (tag == "br") { 69 assert_in_array( 70 editor.innerHTML, 71 [ 72 "<div>abc</div>", 73 "<div>abc<br></div>", 74 ], 75 `The text should be inserted before the <br> element` 76 ); 77 } else { 78 assert_in_array( 79 editor.innerHTML, 80 [ 81 `<div>abc<${tag}></div>`, 82 `<div>abc<${tag}><br></div>`, 83 ], 84 `The text should be inserted before the <${tag}> element` 85 ); 86 } 87 }, `Inserting text when selection is collapsed in <${tag}> which is only child (explicitly flushes maybe pending layout)`); 88 89 test(() => { 90 editor.innerHTML = `<div>abc</div>`; 91 const element = document.createElement(tag); 92 editor.firstChild.appendChild(element); 93 editor.focus(); 94 const selection = getSelection(); 95 selection.collapse(element, 0); 96 document.execCommand("insertText", false, "def"); 97 if (tag == "br") { 98 assert_in_array( 99 editor.innerHTML, 100 [ 101 "<div>abcdef</div>", 102 "<div>abcdef<br></div>", 103 ], 104 `The text should be inserted before the <br> element` 105 ); 106 } else { 107 assert_in_array( 108 editor.innerHTML, 109 [ 110 `<div>abcdef<${tag}></div>`, 111 `<div>abcdef<${tag}><br></div>`, 112 ], 113 `The text should be inserted before the <${tag}> element` 114 ); 115 } 116 }, `Inserting text when selection is collapsed in <${tag}> which follows a text node`); 117 118 test(() => { 119 editor.innerHTML = `<div>def</div>`; 120 const element = document.createElement(tag); 121 editor.firstChild.insertBefore(element, editor.firstChild.firstChild); 122 editor.focus(); 123 const selection = getSelection(); 124 selection.collapse(element, 0); 125 document.execCommand("insertText", false, "abc"); 126 if (tag == "br") { 127 assert_in_array( 128 editor.innerHTML, 129 [ 130 "<div>abc<br>def</div>", 131 "<div>abc<br>def<br></div>", 132 ], 133 `The text should be inserted before the <br> element` 134 ); 135 } else { 136 assert_in_array( 137 editor.innerHTML, 138 [ 139 `<div>abc<${tag}>def</div>`, 140 `<div>abc<${tag}>def<br></div>`, 141 ], 142 `The text should be inserted before the <${tag}> element` 143 ); 144 } 145 }, `Inserting text when selection is collapsed in <${tag}> which is followed by a text node`); 146 147 test(() => { 148 editor.innerHTML = `<div><span></span></div>`; 149 const element = document.createElement(tag); 150 editor.firstChild.appendChild(element); 151 editor.focus(); 152 const selection = getSelection(); 153 selection.collapse(element, 0); 154 document.execCommand("insertText", false, "abc"); 155 if (tag == "br") { 156 assert_in_array( 157 editor.innerHTML, 158 [ 159 "<div><span></span>abc</div>", 160 "<div><span></span>abc<br></div>", 161 ], 162 `The text should be inserted after the previous empty inline element of <br>` 163 ); 164 } else if (tag == "input") { // visible inline? 165 assert_in_array( 166 editor.innerHTML, 167 [ 168 `<div><span></span>abc<${tag}></div>`, 169 `<div><span></span>abc<${tag}><br></div>`, 170 ], 171 `The text should be inserted after the previous empty inline element of <${tag}>` 172 ); 173 } else if (tag == "hr") { // block 174 assert_in_array( 175 editor.innerHTML, 176 [ 177 `<div><span></span>abc<${tag}></div>`, 178 `<div><span></span>abc<br><${tag}></div>`, 179 ], 180 `The text should be inserted after the previous empty inline element of <${tag}>` 181 ); 182 } else { 183 assert_in_array( 184 editor.innerHTML, 185 [ 186 `<div>abc<span></span><${tag}></div>`, 187 `<div>abc<span></span><${tag}><br></div>`, 188 ], 189 `The text should be inserted before the previous empty inline element of <${tag}>` 190 ); 191 } 192 }, `Inserting text when selection is collapsed in <${tag}> which follows an empty <span> element`); 193 194 test(() => { 195 editor.innerHTML = `<div>abc<span></span></div>`; 196 const element = document.createElement(tag); 197 editor.firstChild.appendChild(element); 198 editor.focus(); 199 const selection = getSelection(); 200 selection.collapse(element, 0); 201 document.execCommand("insertText", false, "def"); 202 if (tag == "br") { 203 assert_in_array( 204 editor.innerHTML, 205 [ 206 "<div>abcdef<span></span></div>", 207 "<div>abcdef<span></span><br></div>", 208 ], 209 `The text should be inserted at end of the first text node before empty <span> and <br>` 210 ); 211 } else if (tag == "hr") { // block 212 assert_in_array( 213 editor.innerHTML, 214 [ 215 `<div>abc<span></span>def<${tag}></div>`, 216 `<div>abc<span></span>def<br><${tag}></div>`, 217 ], 218 `The text should be inserted after the previous empty inline element of <${tag}> even if the empty element follows a text node` 219 ); 220 } else { 221 assert_in_array( 222 editor.innerHTML, 223 [ 224 `<div>abcdef<span></span><${tag}></div>`, 225 `<div>abcdef<span></span><${tag}><br></div>`, 226 ], 227 `The text should be inserted before the previous empty inline element of <${tag}>` 228 ); 229 } 230 }, `Inserting text when selection is collapsed in <${tag}> which follows a text node and an empty <span> element`); 231 232 test(() => { 233 editor.innerHTML = `<div><span>abc</span></div>`; 234 const element = document.createElement(tag); 235 editor.firstChild.appendChild(element); 236 editor.focus(); 237 const selection = getSelection(); 238 selection.collapse(element, 0); 239 document.execCommand("insertText", false, "def"); 240 if (tag == "br") { 241 assert_in_array( 242 editor.innerHTML, 243 [ 244 "<div><span>abcdef</span></div>", 245 "<div><span>abcdef</span><br></div>", 246 ], 247 `The text should be inserted at end of the text node in <span>` 248 ); 249 } else if (tag == "hr") { // block 250 assert_in_array( 251 editor.innerHTML, 252 [ 253 `<div><span>abc</span>def<${tag}></div>`, 254 `<div><span>abc</span>def<br><${tag}></div>`, 255 ], 256 `The text should be inserted at after the span and before <${tag}>` 257 ); 258 } else { 259 assert_in_array( 260 editor.innerHTML, 261 [ 262 `<div><span>abcdef</span><${tag}></div>`, 263 `<div><span>abcdef</span><${tag}><br></div>`, 264 ], 265 `The text should be inserted at end of the text node in <span> before <${tag}>` 266 ); 267 } 268 }, `Inserting text when selection is collapsed in <${tag}> which follows a non-empty <span> element`); 269 270 test(() => { 271 editor.innerHTML = `<div>abc<span></span>\n</div>`; 272 const element = document.createElement(tag); 273 editor.firstChild.appendChild(element); 274 editor.focus(); 275 const selection = getSelection(); 276 selection.collapse(element, 0); 277 document.execCommand("insertText", false, "def"); 278 if (tag == "br") { 279 assert_in_array( 280 editor.innerHTML.replace(/\n/g, " "), 281 [ 282 "<div>abcdef<span></span></div>", 283 "<div>abcdef<span></span><br></div>", 284 "<div>abcdef<span></span> </div>", 285 "<div>abcdef<span></span> <br></div>", 286 ], 287 `The text should be inserted at end of the first text node with ignoring the empty <span> and invisible text node before <br>` 288 ); 289 } else if (tag == "img" || tag == "input") { // visible inline 290 assert_in_array( 291 editor.innerHTML.replace(/\n/g, " "), 292 [ 293 `<div>abc<span></span> def<${tag}></div>`, 294 `<div>abc<span></span> def<${tag}><br></div>`, 295 `<div>abc<span></span> def<${tag}></div>`, 296 `<div>abc<span></span> def<${tag}><br></div>`, 297 ], 298 `The text should be inserted at end of the last visible text node` 299 ); 300 } else if (tag == "hr") { // block 301 assert_in_array( 302 editor.innerHTML, 303 [ 304 `<div>abc<span></span>def<${tag}></div>`, 305 `<div>abc<span></span>def<br><${tag}></div>`, 306 ], 307 `The text should be inserted after the previous empty inline element` 308 ); 309 } else { 310 assert_in_array( 311 editor.innerHTML.replace(/\n/g, " "), 312 [ 313 `<div>abcdef<span></span> <${tag}></div>`, 314 `<div>abcdef<span></span> <${tag}><br></div>`, 315 ], 316 `The text should be inserted before the previous empty inline element` 317 ); 318 } 319 }, `Inserting text when selection is collapsed in <${tag}> which follows a text node, an empty <span> element and white-space only text node`); 320 } 321 322 </script>