| <!doctype html> |
| <meta charset=utf-8> |
| <title>Test execCommand with selection around select element</title> |
| <meta name="timeout" content="long"> |
| <meta name="variant" content="?delete"> |
| <meta name="variant" content="?forwardDelete"> |
| <meta name="variant" content="?insertText"> |
| <script src=/resources/testharness.js></script> |
| <script src=/resources/testharnessreport.js></script> |
| <script> |
| "use strict"; |
| |
| const command = document.location.search.substring(1); |
| const insertText = command === "insertText" ? "XYZ" : ""; |
| |
| /** |
| * Typically, browsers do not allow to move caret or select part of <select>, |
| * <option> and <optgroup>, but Selection API can do it (but browsers don't |
| * show the result). In this case, any elements under `<select>` element |
| * shouldn't be modified (deleted) for avoiding unexpected data loss for the |
| * users. |
| */ |
| |
| promise_test(async () => { |
| await new Promise(resolve => { |
| addEventListener("load", resolve, {once: true}); |
| }); |
| }); |
| |
| function addPromiseTest(desc, initFunc, expectedResults) { |
| promise_test(async () => { |
| initFunc(); |
| document.execCommand(command, false, insertText); |
| if (Array.isArray(expectedResults)) { |
| assert_in_array(document.body.innerHTML.replace(/(=""|<br>)/g, ""), expectedResults); |
| } else { |
| assert_equals(document.body.innerHTML.replace(/(=""|<br>)/g, ""), expectedResults); |
| } |
| }, `execCommand(${command}, false, "${insertText}") in ${desc}`); |
| } |
| |
| for (const multiple of ["", " multiple"]) { |
| addPromiseTest( |
| `<div contenteditable><p>ab[c</p><select${multiple}><option>d]ef</option></select></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("p").firstChild, |
| 2, |
| document.querySelector("option").firstChild, |
| 1 |
| ); |
| }, |
| [ |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select></div>`, |
| `<div contenteditable><p>ab${insertText}</p><select${multiple}><option>def</option></select></div>`, |
| ] |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>d[]ef</option></select></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select></div>`; |
| getSelection().collapse( |
| document.querySelector("option").firstChild, |
| 1 |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select></div>`, |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><select${multiple}><option>ab[c</option></select><p>d]ef</p></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><select${multiple}><option>abc</option></select><p>def</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("option").firstChild, |
| 2, |
| document.querySelector("p").firstChild, |
| 1 |
| ); |
| }, |
| [ |
| `<div contenteditable><select${multiple}><option>abc</option></select><p>def</p></div>`, |
| `<div contenteditable><select${multiple}><option>abc</option></select><p>${insertText}ef</p></div>`, |
| ] |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>{}def</option></select><p>ghi</p></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>`; |
| getSelection().collapse( |
| document.querySelector("option"), |
| 0 |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>def{}</option></select><p>ghi</p></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>`; |
| getSelection().collapse( |
| document.querySelector("option"), |
| 1 |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>{def}</option></select><p>ghi</p></div>: shouldn't modify in <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>`; |
| getSelection().selectAllChildren( |
| document.querySelector("option") |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option></select><p>ghi</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>{def</option><option>ghi}</option></select><p>jkl</p></div>: shouldn't join <option>s`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("option"), |
| 0, |
| document.querySelector("option + option"), |
| 1, |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}>{<option>def</option>}<option>ghi</option></select><p>jkl</p></div>: shouldn't delete <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("select"), |
| 0, |
| document.querySelector("select"), |
| 1, |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option>{<option>ghi</option>}</select><p>jkl</p></div>: shouldn't delete <option>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("select"), |
| 1, |
| document.querySelector("select"), |
| 2, |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}>{<option>def</option><option>ghi</option>}</select><p>jkl</p></div>: shouldn't delete <option>s nor <select${multiple}>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().selectAllChildren( |
| document.querySelector("select") |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p><select${multiple}><optgroup>{<option>def</option><option>ghi</option>}</optgroup></select><p>jkl</p></div>: shouldn't delete <option>, <optgroup> nor <select${multiple}>`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><optgroup><option>def</option><option>ghi</option></optgroup></select><p>jkl</p></div>`; |
| getSelection().selectAllChildren( |
| document.querySelector("optgroup") |
| ); |
| }, |
| `<div contenteditable><p>abc</p><select${multiple}><optgroup><option>def</option><option>ghi</option></optgroup></select><p>jkl</p></div>` |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p>{<select${multiple}><option>def</option><option>ghi</option></select>}<p>jkl</p></div>: <select${multiple}> element itself should be removable`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("div"), |
| 1, |
| document.querySelector("div"), |
| 2, |
| ); |
| }, |
| [ |
| `<div contenteditable><p>abc</p>${insertText}<p>jkl</p></div>`, |
| `<div contenteditable><p>abc${insertText}</p><p>jkl</p></div>`, |
| `<div contenteditable><p>abc</p><p>${insertText}jkl</p></div>`, |
| ] |
| ); |
| |
| addPromiseTest( |
| `<div contenteditable><p>abc</p>{<select${multiple}><optgroup><option>def</option><option>ghi</option></optgroup></select>}<p>jkl</p></div>: <select${multiple}> element itself should be removable`, |
| () => { |
| document.body.innerHTML = |
| `<div contenteditable><p>abc</p><select${multiple}><option>def</option><option>ghi</option></select><p>jkl</p></div>`; |
| getSelection().setBaseAndExtent( |
| document.querySelector("div"), |
| 1, |
| document.querySelector("div"), |
| 2, |
| ); |
| }, |
| [ |
| `<div contenteditable><p>abc</p>${insertText}<p>jkl</p></div>`, |
| `<div contenteditable><p>abc${insertText}</p><p>jkl</p></div>`, |
| `<div contenteditable><p>abc</p><p>${insertText}jkl</p></div>`, |
| ] |
| ); |
| |
| addPromiseTest( |
| `<select${multiple} contenteditable>{<option>abc</option><option>def</option>}</select>: shouldn't delete <option>s`, |
| () => { |
| document.body.innerHTML = |
| `<select${multiple} contenteditable><option>abc</option><option>def</option></select>`; |
| getSelection().selectAllChildren( |
| document.querySelector("select") |
| ); |
| }, |
| `<select${multiple} contenteditable><option>abc</option><option>def</option></select>` |
| ); |
| |
| addPromiseTest( |
| `<select${multiple}><option contenteditable>{abc}</option><option>def</option></select>: shouldn't modify <option>`, |
| () => { |
| document.body.innerHTML = |
| `<select${multiple}><option contenteditable>abc</option><option>def</option></select>`; |
| getSelection().selectAllChildren( |
| document.querySelector("option") |
| ); |
| }, |
| `<select${multiple}><option contenteditable>abc</option><option>def</option></select>` |
| ); |
| |
| addPromiseTest( |
| `<select${multiple}><optgroup contenteditable>{<option>abc</option><option>def</option>}</optgroup></select>: shouldn't delete <option>s`, |
| () => { |
| document.body.innerHTML = |
| `<select${multiple}><optgroup contenteditable><option>abc</option><option>def</option></optgroup></select>`; |
| getSelection().selectAllChildren( |
| document.querySelector("optgroup") |
| ); |
| }, |
| `<select${multiple}><optgroup contenteditable><option>abc</option><option>def</option></optgroup></select>` |
| ); |
| |
| addPromiseTest( |
| `<select${multiple}><optgroup contenteditable><option>{abc}</option><option>def</option></optgroup></select>: shouldn't delete <option>s nor optgroup`, |
| () => { |
| document.body.innerHTML = |
| `<select${multiple}><optgroup contenteditable><option>abc</option><option>def</option></optgroup></select>`; |
| getSelection().selectAllChildren( |
| document.querySelector("option") |
| ); |
| }, |
| `<select${multiple}><optgroup contenteditable><option>abc</option><option>def</option></optgroup></select>` |
| ); |
| } |
| |
| addPromiseTest( |
| "<optgroup contenteditable><option>{abc}</option><option>def</option></optgroup>: shouldn't delete <option>s nor optgroup", |
| () => { |
| document.body.innerHTML = |
| "<optgroup contenteditable><option>abc</option><option>def</option></optgroup>"; |
| getSelection().selectAllChildren( |
| document.querySelector("option") |
| ); |
| }, |
| `<optgroup contenteditable><option>abc</option><option>def</option></optgroup>` |
| ); |
| |
| addPromiseTest( |
| "<option contenteditable>{abc}</option>: shouldn't modify <option>", |
| () => { |
| document.body.innerHTML = |
| "<option contenteditable>abc</option>"; |
| getSelection().selectAllChildren( |
| document.querySelector("option") |
| ); |
| }, |
| `<option contenteditable>abc</option>` |
| ); |
| </script> |
| <body></body> |