insertparagraph-with-white-space-style.tentative.html (22930B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <meta name="timeout" content="long"> 4 <meta name="variant" content="?white-space=pre&command=insertParagraph"> 5 <meta name="variant" content="?white-space=pre-wrap&command=insertParagraph"> 6 <meta name="variant" content="?white-space=pre-line&command=insertParagraph"> 7 <meta name="variant" content="?white-space=nowrap&command=insertParagraph"> 8 <meta name="variant" content="?white-space=pre&command=insertText"> 9 <meta name="variant" content="?white-space=pre-wrap&command=insertText"> 10 <meta name="variant" content="?white-space=pre-line&command=insertText"> 11 <meta name="variant" content="?white-space=nowrap&command=insertText"> 12 <script src="/resources/testharness.js"></script> 13 <script src="/resources/testharnessreport.js"></script> 14 <script src="../include/editor-test-utils.js"></script> 15 <link rel=stylesheet href=../include/reset.css> 16 <title>insertparagraph in white-space specified element</title> 17 <body><div contenteditable></div></body> 18 <script> 19 /** 20 * This test checks how insertParagraph command and insertText of "\n" works 21 * in valid styles of parent (editing host itself or in an splittable element). 22 */ 23 const params = new URLSearchParams(location.search); 24 const style = params.get("white-space"); 25 const isNewLineSignificant = style == "pre" || style == "pre-wrap" || style == "pre-line"; 26 const command = params.get("command"); 27 const editingHost = document.querySelector("div[contenteditable]"); 28 function execInsertTextOrParagraphCommand() { 29 if (command == "insertParagraph") { 30 document.execCommand(command); 31 } else { 32 // Inserting a linefeed by insertText command should be equivalent of insertParagraph 33 document.execCommand(command, false, "\n"); 34 } 35 } 36 for (const defaultParagraphSeparator of ["div", "p"]) { 37 document.execCommand("defaultParagraphSeparator", false, defaultParagraphSeparator); 38 for (const display of ["block", "inline", "inline-block"]) { 39 // Inserting paragraph or inserting a linefeed in a text node which is 40 // a direct child of the editing host. 41 test(() => { 42 editingHost.style.whiteSpace = style; 43 editingHost.style.display = display; 44 const utils = new EditorTestUtils(editingHost); 45 utils.setupEditingHost(`abc[]`); 46 editingHost.getBoundingClientRect(); 47 execInsertTextOrParagraphCommand(); 48 // If the editing host is a block, at least the new paragraph should be 49 // the default paragraph separator element. 50 if (display == "block") { 51 assert_in_array( 52 editingHost.innerHTML, 53 [ 54 `abc<${defaultParagraphSeparator}><br></${defaultParagraphSeparator}>`, 55 `<${defaultParagraphSeparator}>abc</${defaultParagraphSeparator}><${defaultParagraphSeparator}><br></${defaultParagraphSeparator}>`, 56 ], 57 "New paragraph should be inserted at end of the editing host" 58 ); 59 } 60 // Otherwise, i.e., the editing host is inline, insert a line break (a 61 // linefeed or <br>) should be inserted instead because it's better 62 // look for the users. 63 // Note that an extra line break is required for making the last line 64 // visible because the editing host is the last visible inline in the 65 // parent block (<body>). 66 else if (isNewLineSignificant) { 67 assert_in_array( 68 editingHost.innerHTML, 69 [ 70 `abc\n\n`, 71 `abc\n<br>`, 72 ], 73 "A linefeed should be inserted at end" 74 ); 75 } else { 76 assert_equals( 77 editingHost.innerHTML, 78 `abc<br><br>`, 79 "A <br> should be inserted at end" 80 ); 81 } 82 }, `<div contenteditable style="white-space:${style}; display:${display}">abc[]</div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 83 84 // Same as above test except the caret position. 85 test(() => { 86 editingHost.style.whiteSpace = style; 87 editingHost.style.display = display; 88 const utils = new EditorTestUtils(editingHost); 89 utils.setupEditingHost(`[]abc`); 90 editingHost.getBoundingClientRect(); 91 execInsertTextOrParagraphCommand(); 92 if (display == "block") { 93 assert_in_array( 94 editingHost.innerHTML, 95 [ 96 `<${defaultParagraphSeparator}><br></${defaultParagraphSeparator}>abc`, 97 `<${defaultParagraphSeparator}><br></${defaultParagraphSeparator}><${defaultParagraphSeparator}>abc</${defaultParagraphSeparator}>`, 98 ], 99 "New paragraph should be inserted at start of the editing host" 100 ); 101 } else if (isNewLineSignificant) { 102 assert_in_array( 103 editingHost.innerHTML, 104 [ 105 `\nabc`, 106 `\nabc<br>`, 107 ], 108 "A linefeed should be inserted at start" 109 ); 110 } else { 111 assert_in_array( 112 editingHost.innerHTML, 113 [ 114 `<br>abc`, 115 `<br>abc<br>`, 116 ], 117 "A <br> should be inserted at start" 118 ); 119 } 120 }, `<div contenteditable style="white-space:${style}; display:${display}">[]abc</div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 121 122 // Same as above test except the caret position. 123 test(() => { 124 editingHost.style.whiteSpace = style; 125 editingHost.style.display = display; 126 const utils = new EditorTestUtils(editingHost); 127 utils.setupEditingHost(`a[]bc`); 128 editingHost.getBoundingClientRect(); 129 execInsertTextOrParagraphCommand(); 130 if (display == "block") { 131 assert_in_array( 132 editingHost.innerHTML, 133 [ 134 `a<${defaultParagraphSeparator}>bc</${defaultParagraphSeparator}>`, 135 `<${defaultParagraphSeparator}>a</${defaultParagraphSeparator}><${defaultParagraphSeparator}>bc</${defaultParagraphSeparator}>`, 136 ], 137 "New paragraph should split the text" 138 ); 139 } else if (isNewLineSignificant) { 140 assert_in_array( 141 editingHost.innerHTML, 142 [ 143 `a\nbc`, 144 `a\nbc<br>`, 145 ], 146 "A linefeed should be inserted" 147 ); 148 } else { 149 assert_in_array( 150 editingHost.innerHTML, 151 [ 152 `a<br>bc`, 153 `a<br>bc<br>`, 154 ], 155 "A <br> should be inserted" 156 ); 157 } 158 }, `<div contenteditable style="white-space:${style}; display:${display}">a[]bc</div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 159 160 // Inserting paragraph or inserting a linefeed in a text node after 161 // executing the "italic" command. The paragraph or line break result 162 // should be same as above, but the text in the new paragraph or new line 163 // should be wrapped in <i>. 164 test(() => { 165 editingHost.style.whiteSpace = style; 166 editingHost.style.display = display; 167 const utils = new EditorTestUtils(editingHost); 168 utils.setupEditingHost(`abc[]`); 169 editingHost.getBoundingClientRect(); 170 document.execCommand("italic"); 171 execInsertTextOrParagraphCommand(); 172 document.execCommand("inserttext", false, "def"); 173 if (display == "block") { 174 assert_in_array( 175 editingHost.innerHTML, 176 [ 177 `abc<${defaultParagraphSeparator}><i>def</i></${defaultParagraphSeparator}>`, 178 `<${defaultParagraphSeparator}>abc</${defaultParagraphSeparator}><${defaultParagraphSeparator}><i>def</i></${defaultParagraphSeparator}>`, 179 `<${defaultParagraphSeparator}>abc</${defaultParagraphSeparator}><${defaultParagraphSeparator}><i>def<br></i></${defaultParagraphSeparator}>`, 180 `<${defaultParagraphSeparator}>abc</${defaultParagraphSeparator}><${defaultParagraphSeparator}><i>def</i><br></${defaultParagraphSeparator}>`, 181 ], 182 "New paragraph should be inserted at end of the editing host whose text should be italic" 183 ); 184 } else if (isNewLineSignificant) { 185 assert_in_array( 186 editingHost.innerHTML, 187 [ 188 `abc\n<i>def</i>`, 189 `abc\n<i>def\n</i>`, 190 `abc\n<i>def<br></i>`, 191 `abc\n<i>def</i>\n`, 192 `abc\n<i>def</i><br>`, 193 ], 194 "The new line should be italic" 195 ); 196 } else { 197 assert_in_array( 198 editingHost.innerHTML, 199 [ 200 `abc<br><i>def</i>`, 201 `abc<br><i>def<br></i>`, 202 `abc<br><i>def</i><br>`, 203 ], 204 "The new line should be italic" 205 ); 206 } 207 }, `<div contenteditable style="white-space:${style}; display:${display}">abc[]</div> (defaultParagraphSeparator: ${defaultParagraphSeparator}) (preserving temporary inline style test)`); 208 209 // Inserting paragraph or inserting a linefeed in a text node which is 210 // wrapped in a <b>. The paragraph or line break result should be same as 211 // above, but the <b> element should be duplicated in the new paragraph 212 // or shouldn't be split if inserting a line break. 213 test(() => { 214 editingHost.style.whiteSpace = style; 215 editingHost.style.display = display; 216 const utils = new EditorTestUtils(editingHost); 217 utils.setupEditingHost(`<b>abc[]</b>`); 218 editingHost.getBoundingClientRect(); 219 execInsertTextOrParagraphCommand(); 220 document.execCommand("inserttext", false, "def"); 221 if (display == "block") { 222 assert_in_array( 223 editingHost.innerHTML, 224 [ 225 `<b>abc</b><${defaultParagraphSeparator}><b>def</b></${defaultParagraphSeparator}>`, 226 `<${defaultParagraphSeparator}><b>abc</b></${defaultParagraphSeparator}><${defaultParagraphSeparator}><b>def</b></${defaultParagraphSeparator}>`, 227 `<${defaultParagraphSeparator}><b>abc</b></${defaultParagraphSeparator}><${defaultParagraphSeparator}><b>def<br></b></${defaultParagraphSeparator}>`, 228 `<${defaultParagraphSeparator}><b>abc</b></${defaultParagraphSeparator}><${defaultParagraphSeparator}><b>def</b><br></${defaultParagraphSeparator}>`, 229 ], 230 "New paragraph should be inserted at end of the editing host whose text should be bold" 231 ); 232 } else if (isNewLineSignificant) { 233 assert_in_array( 234 editingHost.innerHTML, 235 [ 236 `<b>abc\ndef</b>`, 237 `<b>abc\ndef\n</b>`, 238 `<b>abc\ndef<br></b>`, 239 `<b>abc\ndef</b>\n`, 240 `<b>abc\ndef</b><br>`, 241 ], 242 "The new line should be bold" 243 ); 244 } else { 245 assert_in_array( 246 editingHost.innerHTML, 247 [ 248 `<b>abc<br>def</b>`, 249 `<b>abc<br>def<br></b>`, 250 `<b>abc<br>def</b><br>`, 251 ], 252 "The new line should be bold" 253 ); 254 } 255 }, `<div contenteditable style="white-space:${style}; display:${display}"><b>abc[]</b></div> (defaultParagraphSeparator: ${defaultParagraphSeparator}) (preserving inline style test)`); 256 257 for (const paragraph of ["div", "p"]) { 258 // Inserting paragraph or inserting a linefeed in a splittable paragraph 259 // (<p> or <div>) whose `white-space` is specified. 260 test(() => { 261 editingHost.style.whiteSpace = "normal"; 262 editingHost.style.display = display; 263 const utils = new EditorTestUtils(editingHost); 264 utils.setupEditingHost(`<${paragraph} style="white-space:${style}">abc[]</${paragraph}>`); 265 editingHost.getBoundingClientRect(); 266 execInsertTextOrParagraphCommand(); 267 // Even if the editing host is inline, the command should be handled 268 // with in the splittable paragraph. Therefore, the paragraph should 269 // be just split and the style attribute should be cloned to keep same 270 // style in the new paragraph. 271 assert_equals( 272 editingHost.innerHTML, 273 `<${paragraph} style="white-space:${style}">abc</${paragraph}><${paragraph} style="white-space:${style}"><br></${paragraph}>`, 274 "New paragraph should be inserted at end of the paragraph" 275 ); 276 }, `<div contenteditable style="display:${display}"><${paragraph} style="white-space:${style}">abc[]</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 277 278 // Same as above test except the caret position. 279 test(() => { 280 editingHost.style.whiteSpace = "normal"; 281 editingHost.style.display = display; 282 const utils = new EditorTestUtils(editingHost); 283 utils.setupEditingHost(`<${paragraph} style="white-space:${style}">[]abc</${paragraph}>`); 284 editingHost.getBoundingClientRect(); 285 execInsertTextOrParagraphCommand(); 286 assert_in_array( 287 editingHost.innerHTML, 288 [ 289 `<${paragraph} style="white-space:${style}"><br></${paragraph}><${paragraph} style="white-space:${style}">abc</${paragraph}>`, 290 `<${paragraph} style="white-space:${style}"><br></${paragraph}><${paragraph} style="white-space:${style}">abc<br></${paragraph}>`, 291 ], 292 "New paragraph should be inserted at start of the paragraph" 293 ); 294 }, `<div contenteditable style="display:${display}"><${paragraph} style="white-space:${style}">[]abc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 295 296 // Same as above test except the caret position. 297 test(() => { 298 editingHost.style.whiteSpace = "normal"; 299 editingHost.style.display = display; 300 const utils = new EditorTestUtils(editingHost); 301 utils.setupEditingHost(`<${paragraph} style="white-space:${style}">a[]bc</${paragraph}>`); 302 editingHost.getBoundingClientRect(); 303 execInsertTextOrParagraphCommand(); 304 assert_in_array( 305 editingHost.innerHTML, 306 [ 307 `<${paragraph} style="white-space:${style}">a</${paragraph}><${paragraph} style="white-space:${style}">bc</${paragraph}>`, 308 `<${paragraph} style="white-space:${style}">a</${paragraph}><${paragraph} style="white-space:${style}">bc<br></${paragraph}>`, 309 ], 310 "The paragraph should be split" 311 ); 312 }, `<div contenteditable style="display:${display}"><${paragraph} style="white-space:${style}">a[]bc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 313 314 // Inserting paragraph or inserting a linefeed in a splittable paragraph 315 // in the editing host whose `white-space` is specified. 316 test(() => { 317 editingHost.style.whiteSpace = style; 318 editingHost.style.display = display; 319 const utils = new EditorTestUtils(editingHost); 320 utils.setupEditingHost(`<${paragraph}>abc[]</${paragraph}>`); 321 editingHost.getBoundingClientRect(); 322 execInsertTextOrParagraphCommand(); 323 // Same as previous tests, the splittable paragraph should be split. 324 // The `white-space` style of the ancestor block or the inline editing 325 // host should not affect to the behavior because we can just split 326 // the paragraph. 327 assert_equals( 328 editingHost.innerHTML, 329 `<${paragraph}>abc</${paragraph}><${paragraph}><br></${paragraph}>`, 330 "New paragraph should be inserted at end of the paragraph" 331 ); 332 }, `<div contenteditable style="display:${display}; white-space:${style}"><${paragraph}>abc[]</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 333 334 // Same as above test except the caret position. 335 test(() => { 336 editingHost.style.whiteSpace = style; 337 editingHost.style.display = display; 338 const utils = new EditorTestUtils(editingHost); 339 utils.setupEditingHost(`<${paragraph}>[]abc</${paragraph}>`); 340 editingHost.getBoundingClientRect(); 341 execInsertTextOrParagraphCommand(); 342 assert_in_array( 343 editingHost.innerHTML, 344 [ 345 `<${paragraph}><br></${paragraph}><${paragraph}>abc</${paragraph}>`, 346 `<${paragraph}><br></${paragraph}><${paragraph}>abc<br></${paragraph}>`, 347 ], 348 "New paragraph should be inserted at start of the paragraph" 349 ); 350 }, `<div contenteditable style="display:${display}; white-space:${style}"><${paragraph}>[]abc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 351 352 // Same as above test except the caret position. 353 test(() => { 354 editingHost.style.whiteSpace = style; 355 editingHost.style.display = display; 356 const utils = new EditorTestUtils(editingHost); 357 utils.setupEditingHost(`<${paragraph}>a[]bc</${paragraph}>`); 358 editingHost.getBoundingClientRect(); 359 execInsertTextOrParagraphCommand(); 360 assert_in_array( 361 editingHost.innerHTML, 362 [ 363 `<${paragraph}>a</${paragraph}><${paragraph}>bc</${paragraph}>`, 364 `<${paragraph}>a</${paragraph}><${paragraph}>bc<br></${paragraph}>`, 365 ], 366 "The paragraph should be split" 367 ); 368 }, `<div contenteditable style="display:${display}; white-space:${style}"><${paragraph}>a[]bc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 369 370 // Inserting paragraph or inserting a linefeed in a splittable paragraph 371 // element whose `display` and `white-space` are specified. 372 test(() => { 373 editingHost.style.whiteSpace = "normal"; 374 editingHost.style.display = "block"; 375 const utils = new EditorTestUtils(editingHost); 376 const styleAttr = `style="display:${display}; white-space:${style}"`; 377 utils.setupEditingHost(`<${paragraph} ${styleAttr}>abc[]</${paragraph}>`); 378 editingHost.getBoundingClientRect(); 379 execInsertTextOrParagraphCommand(); 380 // If the paragraph is a normal block, we can just split the paragraph. 381 if (display == "block") { 382 assert_equals( 383 editingHost.innerHTML, 384 `<${paragraph} ${styleAttr}>abc</${paragraph}><${paragraph} ${styleAttr}><br></${paragraph}>`, 385 "New paragraph should be inserted at end of the paragraph" 386 ); 387 } 388 // Otherwise, the paragraph is an inline, splitting the paragraph 389 // element does not look like inserting paragraph for the users 390 // because it would just duplicate the inlined element. 391 // Therefore, the split paragraph should be wrapped into the new 392 // paragraph (considered with the default paragraph separator) at 393 // least. However, <p> cannot contain <p> nor <div> which may be 394 // styled as inline. Therefore, <div> should be used for the new 395 // paragraph even if the default paragraph separator is <p>. 396 else { 397 assert_in_array( 398 editingHost.innerHTML, 399 [ 400 `<${paragraph} ${styleAttr}>abc</${paragraph}><div><${paragraph} ${styleAttr}><br></${paragraph}></div>`, 401 `<div><${paragraph} ${styleAttr}>abc</${paragraph}></div><div><${paragraph} ${styleAttr}><br></${paragraph}></div>`, 402 ], 403 "New paragraph should be inserted at end of the paragraph which is wrapped by a new <div>" 404 ); 405 } 406 }, `<div contenteditable><${paragraph} style="display:${display}; white-space:${style}">abc[]</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 407 408 // Same as above test except the caret position. 409 test(() => { 410 editingHost.style.whiteSpace = "normal"; 411 editingHost.style.display = "block"; 412 const utils = new EditorTestUtils(editingHost); 413 const styleAttr = `style="display:${display}; white-space:${style}"`; 414 utils.setupEditingHost(`<${paragraph} ${styleAttr}>[]abc</${paragraph}>`); 415 editingHost.getBoundingClientRect(); 416 execInsertTextOrParagraphCommand(); 417 if (display == "block") { 418 assert_in_array( 419 editingHost.innerHTML, 420 [ 421 `<${paragraph} ${styleAttr}><br></${paragraph}><${paragraph} ${styleAttr}>abc</${paragraph}>`, 422 `<${paragraph} ${styleAttr}><br></${paragraph}><${paragraph} ${styleAttr}>abc<br></${paragraph}>`, 423 ], 424 "New paragraph should be inserted at start of the paragraph" 425 ); 426 } else { 427 assert_in_array( 428 editingHost.innerHTML, 429 [ 430 `<div><${paragraph} ${styleAttr}><br></${paragraph}></div><${paragraph} ${styleAttr}>abc</${paragraph}>`, 431 `<div><${paragraph} ${styleAttr}><br></${paragraph}></div><${paragraph} ${styleAttr}>abc<br></${paragraph}>`, 432 `<div><${paragraph} ${styleAttr}><br></${paragraph}></div><div><${paragraph} ${styleAttr}>abc</${paragraph}></div>`, 433 `<div><${paragraph} ${styleAttr}><br></${paragraph}></div><div><${paragraph} ${styleAttr}>abc<br></${paragraph}></div>`, 434 ], 435 "New paragraph should be inserted at start of the paragraph which is wrapped by a new <div>" 436 ); 437 } 438 439 }, `<div contenteditable><${paragraph} style="display:${display}; white-space:${style}">[]abc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 440 441 // Same as above test except the caret position. 442 test(() => { 443 editingHost.style.whiteSpace = "normal"; 444 editingHost.style.display = "block"; 445 const styleAttr = `style="display:${display}; white-space:${style}"`; 446 const utils = new EditorTestUtils(editingHost); 447 utils.setupEditingHost(`<${paragraph} ${styleAttr}>a[]bc</${paragraph}>`); 448 editingHost.getBoundingClientRect(); 449 execInsertTextOrParagraphCommand(); 450 if (display == "block") { 451 assert_in_array( 452 editingHost.innerHTML, 453 [ 454 `<${paragraph} ${styleAttr}>a</${paragraph}><${paragraph} ${styleAttr}>bc</${paragraph}>`, 455 `<${paragraph} ${styleAttr}>a</${paragraph}><${paragraph} ${styleAttr}>bc<br></${paragraph}>`, 456 ], 457 "The paragraph should be split" 458 ); 459 } else { 460 assert_in_array( 461 editingHost.innerHTML, 462 [ 463 `<${paragraph} ${styleAttr}>a</${paragraph}><div><${paragraph} ${styleAttr}>bc</${paragraph}></div>`, 464 `<${paragraph} ${styleAttr}>a</${paragraph}><div><${paragraph} ${styleAttr}>bc<br></${paragraph}></div>`, 465 `<div><${paragraph} ${styleAttr}>a</${paragraph}></div><div><${paragraph} ${styleAttr}>bc</${paragraph}></div>`, 466 `<div><${paragraph} ${styleAttr}>a</${paragraph}></div><div><${paragraph} ${styleAttr}>bc<br></${paragraph}></div>`, 467 ], 468 "The paragraph should be split and the latter one should be wrapped by a new <div>" 469 ); 470 } 471 }, `<div contenteditable><${paragraph} style="display:${display}; white-space:${style}">a[]bc</${paragraph}></div> (defaultParagraphSeparator: ${defaultParagraphSeparator})`); 472 } 473 } 474 } 475 </script>