Range_setStart.html (23562B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>focus move tests caused by a call of Range.setStart(), Range.setStartAfter() and Range.setStartBefore()</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <body> 7 <div style="height: 3000px;">Spacer to check whether or not page was scrolled down to focused editor</div> 8 <p id="staticBefore">static text</p> 9 <div id="editor" contenteditable><p>content of editor</p></div> 10 <div id="outerEditor" contenteditable 11 ><p>content of outer editor</p><div id="staticInEditor" contenteditable="false" 12 ><p>static content of outer editor</p><div id="innerEditor" contenteditable 13 ><p>content of inner editor</p></div></div></div> 14 <p id="staticAfter">static text</p> 15 <p><a id="anchor" href="about:blank">anchor</a></p> 16 <script> 17 "use strict"; 18 19 var staticBefore = { 20 element: document.getElementById("staticBefore"), 21 textNode: document.getElementById("staticBefore").firstChild, 22 textLength: document.getElementById("staticBefore").firstChild.length 23 }; 24 var editor = { 25 element: document.getElementById("editor"), 26 textNode: document.getElementById("editor").firstChild.firstChild, 27 textLength: document.getElementById("editor").firstChild.firstChild.length 28 }; 29 var outerEditor = { 30 element: document.getElementById("outerEditor"), 31 textNode: document.getElementById("outerEditor").firstChild.firstChild, 32 textLength: document.getElementById("outerEditor").firstChild.firstChild.length 33 }; 34 var staticInEditor = { 35 element: document.getElementById("staticInEditor"), 36 textNode: document.getElementById("staticInEditor").firstChild, 37 textLength: document.getElementById("staticInEditor").firstChild.length 38 }; 39 var innerEditor = { 40 element: document.getElementById("innerEditor"), 41 textNode: document.getElementById("innerEditor").firstChild.firstChild, 42 textLength: document.getElementById("innerEditor").firstChild.firstChild.length 43 }; 44 var staticAfter = { 45 element: document.getElementById("staticAfter"), 46 textNode: document.getElementById("staticAfter").firstChild, 47 textLength: document.getElementById("staticAfter").firstChild.length 48 }; 49 var anchor = { 50 element: document.getElementById("anchor"), 51 textNode: document.getElementById("anchor").firstChild, 52 textLength: document.getElementById("anchor").firstChild.length 53 }; 54 55 function resetFocusAndSelectionRange(aFocus) 56 { 57 document.getSelection().removeAllRanges(); 58 if (document.activeElement) { 59 document.activeElement.blur(); 60 } 61 if (aFocus) { 62 aFocus.element.focus(); 63 document.getSelection().collapse(aFocus.textNode, 0); 64 } else { 65 document.getSelection().collapse(staticBefore.textNode, 0); 66 } 67 document.documentElement.scrollTop = 0; 68 } 69 70 function setStart(aNode, aOffset) 71 { 72 document.getSelection().getRangeAt(0).setStart(aNode, aOffset); 73 } 74 75 function setStartBefore(aNode, aOffset) 76 { 77 document.getSelection().getRangeAt(0).setStartBefore(aNode); 78 } 79 80 function setStartAfter(aNode, aOffset) 81 { 82 document.getSelection().getRangeAt(0).setStartAfter(aNode); 83 } 84 85 // Range.setStart*() should work same as collapse if specified start position is after its end. 86 [{ func: setStart, doingDescription: "Range.setStart()" }, 87 { func: setStartAfter, doingDescription: "Range.setStartAfter()" }].forEach((aTest, aIndex, aArray)=>{ 88 test(function() { 89 resetFocusAndSelectionRange(); 90 document.getSelection().selectAllChildren(staticBefore.textNode); 91 aTest.func(editor.textNode, editor.textLength); 92 assert_equals(document.activeElement, editor.element); 93 assert_equals(document.documentElement.scrollTop, 0); 94 }, "Active element should be 'editor' after " + aTest.doingDescription + " with end of the first text node of 'editor' (before the selection) when active element is the <body>"); 95 test(function() { 96 resetFocusAndSelectionRange(editor); 97 document.getSelection().selectAllChildren(editor.textNode); 98 aTest.func(outerEditor.textNode, outerEditor.textLength); 99 assert_equals(document.activeElement, outerEditor.element); 100 assert_equals(document.documentElement.scrollTop, 0); 101 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'outerEditor' (before the selection) when active element is 'editor'"); 102 test(function() { 103 resetFocusAndSelectionRange(outerEditor); 104 document.getSelection().selectAllChildren(outerEditor.textNode); 105 aTest.func(staticInEditor.textNode, staticInEditor.textLength); 106 assert_equals(document.activeElement, outerEditor.element); 107 assert_equals(document.documentElement.scrollTop, 0); 108 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticInEditor' (before the selection) when active element is 'outerEditor'"); 109 test(function() { 110 resetFocusAndSelectionRange(); 111 document.getSelection().selectAllChildren(staticInEditor.textNode); 112 aTest.func(innerEditor.textNode, innerEditor.textLength); 113 assert_equals(document.activeElement, innerEditor.element); 114 assert_equals(document.documentElement.scrollTop, 0); 115 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'innerEditor' (before the selection) when active element is the <body> and selection is in 'staticInEditor'"); 116 test(function() { 117 resetFocusAndSelectionRange(innerEditor); 118 document.getSelection().selectAllChildren(innerEditor.textNode); 119 aTest.func(staticAfter.textNode, staticAfter.textLength); 120 assert_equals(document.activeElement, innerEditor.element); 121 assert_equals(document.documentElement.scrollTop, 0); 122 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticAfter' (before the selection) when active element is 'innerEditor'"); 123 124 test(function() { 125 resetFocusAndSelectionRange(); 126 document.getSelection().collapse(staticBefore.textNode, 0); 127 aTest.func(editor.textNode, editor.textLength); 128 assert_equals(document.activeElement, editor.element); 129 assert_equals(document.documentElement.scrollTop, 0); 130 }, "Active element should be 'editor' after " + aTest.doingDescription + " with end of the first text node of 'editor' (before the collapsed selection) when active element is the <body>"); 131 test(function() { 132 resetFocusAndSelectionRange(editor); 133 document.getSelection().collapse(editor.textNode, 0); 134 aTest.func(outerEditor.textNode, outerEditor.textLength); 135 assert_equals(document.activeElement, outerEditor.element); 136 assert_equals(document.documentElement.scrollTop, 0); 137 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'outerEditor' (before the collapsed selection) when active element is 'editor'"); 138 test(function() { 139 resetFocusAndSelectionRange(outerEditor); 140 document.getSelection().collapse(outerEditor.textNode, 0); 141 aTest.func(staticInEditor.textNode, staticInEditor.textLength); 142 assert_equals(document.activeElement, outerEditor.element); 143 assert_equals(document.documentElement.scrollTop, 0); 144 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticInEditor' (before the collapsed selection) when active element is 'outerEditor'"); 145 test(function() { 146 resetFocusAndSelectionRange(); 147 document.getSelection().collapse(staticInEditor.textNode, 0); 148 aTest.func(innerEditor.textNode, innerEditor.textLength); 149 assert_equals(document.activeElement, innerEditor.element); 150 assert_equals(document.documentElement.scrollTop, 0); 151 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'innerEditor' (before the collapsed selection) when active element is the <body> and selection is in 'staticInEditor'"); 152 test(function() { 153 resetFocusAndSelectionRange(innerEditor); 154 document.getSelection().collapse(innerEditor.textNode, 0); 155 aTest.func(staticAfter.textNode, staticAfter.textLength); 156 assert_equals(document.activeElement, innerEditor.element); 157 assert_equals(document.documentElement.scrollTop, 0); 158 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticAfter' (before the collapsed selection) when active element is 'innerEditor'"); 159 160 test(function() { 161 resetFocusAndSelectionRange(); 162 document.getSelection().setBaseAndExtent(staticBefore.textNode, 0, 163 editor.textNode, 0); 164 aTest.func(editor.textNode, editor.textLength); 165 assert_equals(document.activeElement, editor.element); 166 assert_equals(document.documentElement.scrollTop, 0); 167 }, "Active element should be 'editor' after " + aTest.doingDescription + " with end of the first text node of 'editor' (before the selection, between start of the first text node of 'staticBefore' and start of the first text node of 'editor') when active element is the <body>"); 168 test(function() { 169 resetFocusAndSelectionRange(); 170 document.getSelection().setBaseAndExtent(editor.textNode, 0, 171 outerEditor.textNode, 0); 172 aTest.func(outerEditor.textNode, outerEditor.textLength); 173 assert_equals(document.activeElement, outerEditor.element); 174 assert_equals(document.documentElement.scrollTop, 0); 175 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'outerEditor' (before the selection, between start of the first text node of 'editor' and start of the first text node of 'outerEditor') when active element is the <body>"); 176 test(function() { 177 resetFocusAndSelectionRange(outerEditor); 178 document.getSelection().setBaseAndExtent(outerEditor.textNode, 0, 179 staticInEditor.textNode, 0); 180 aTest.func(staticInEditor.textNode, staticInEditor.textLength); 181 assert_equals(document.activeElement, outerEditor.element); 182 assert_equals(document.documentElement.scrollTop, 0); 183 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticInEditor' (before the selection, between start of the first text node of 'outerEditor' and start of the first text node of 'staticInEditor') when active element is 'outerEditor'"); 184 test(function() { 185 resetFocusAndSelectionRange(outerEditor); 186 document.getSelection().setBaseAndExtent(outerEditor.textNode, 0, 187 innerEditor.textNode, 0); 188 aTest.func(innerEditor.textNode, innerEditor.textLength); 189 assert_equals(document.activeElement, innerEditor.element); 190 assert_equals(document.documentElement.scrollTop, 0); 191 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'innerEditor' (before the selection, between start of the first text node of 'outerEditor' and start of the first text node of 'innerEditor') when active element is 'outerEditor'"); 192 test(function() { 193 resetFocusAndSelectionRange(); 194 document.getSelection().setBaseAndExtent(staticInEditor.textNode, 0, 195 innerEditor.textNode, 0); 196 aTest.func(innerEditor.textNode, innerEditor.textLength); 197 assert_equals(document.activeElement, innerEditor.element); 198 assert_equals(document.documentElement.scrollTop, 0); 199 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'innerEditor' (before the selection, between start of the first text node of 'staticInEditor' and start of the first text node of 'innerEditor') when active element is the <body>"); 200 test(function() { 201 resetFocusAndSelectionRange(); 202 document.getSelection().setBaseAndExtent(innerEditor.textNode, 0, 203 staticAfter.textNode, 0); 204 aTest.func(staticAfter.textNode, staticAfter.textLength); 205 assert_equals(document.activeElement, document.body); 206 assert_equals(document.documentElement.scrollTop, 0); 207 }, "Active element should be the <body> after " + aTest.doingDescription + " with end of the first text node of 'staticAfter' (before the selection, between start of the first text node of 'innerEditor' and start of the first text node of 'staticAfter') when active element is the <body>"); 208 }); 209 210 test(function() { 211 resetFocusAndSelectionRange(); 212 document.getSelection().selectAllChildren(staticBefore.textNode); 213 setStartBefore(editor.textNode); 214 assert_equals(document.activeElement, editor.element); 215 assert_equals(document.documentElement.scrollTop, 0); 216 }, "Active element should be 'editor' after Range.setStartBefore() with the first text node of 'editor' (before the selection) when active element is the <body>"); 217 test(function() { 218 resetFocusAndSelectionRange(editor); 219 document.getSelection().selectAllChildren(editor.textNode); 220 setStartBefore(outerEditor.textNode); 221 assert_equals(document.activeElement, outerEditor.element); 222 assert_equals(document.documentElement.scrollTop, 0); 223 }, "Active element should be 'outerEditor' after Range.setStartBefore() with the first text node of 'outerEditor' (before the selection) when active element is 'editor'"); 224 test(function() { 225 resetFocusAndSelectionRange(outerEditor); 226 document.getSelection().selectAllChildren(outerEditor.textNode); 227 setStartBefore(innerEditor.textNode); 228 assert_equals(document.activeElement, innerEditor.element); 229 assert_equals(document.documentElement.scrollTop, 0); 230 }, "Active element should be 'innerEditor' after Range.setStartBefore() with the first text node of 'innerEditor' (before the selection) when active element is 'outerEditor'"); 231 test(function() { 232 resetFocusAndSelectionRange(innerEditor); 233 document.getSelection().selectAllChildren(innerEditor.textNode); 234 setStartBefore(staticAfter.textNode); 235 assert_equals(document.activeElement, innerEditor.element); 236 assert_equals(document.documentElement.scrollTop, 0); 237 }, "Active element should be 'innerEditor' after Range.setStartBefore() with the first text node of 'innerEditor' (before the selection) when active element is 'innerEditor'"); 238 test(function() { 239 resetFocusAndSelectionRange(); 240 document.getSelection().selectAllChildren(staticAfter.textNode); 241 setStartBefore(anchor.textNode); 242 assert_equals(document.activeElement, document.body); 243 assert_equals(document.documentElement.scrollTop, 0); 244 }, "Active element should be the <body> after Range.setStartBefore() with the first text node of 'anchor' (before the selection) when active element is the <body>"); 245 246 // Range.setStart*() should blur focused editing host when it expands selection to outside of it. 247 [{ func: setStart, doingDescription: "Range.setStart()" }, 248 { func: setStartAfter, doingDescription: "Range.setStartAfter()" }, 249 { func: setStartBefore, doingDescription: "Range.setStartBefore()" }].forEach((aTest, aIndex, aArray)=>{ 250 test(function() { 251 resetFocusAndSelectionRange(editor); 252 document.getSelection().collapse(editor.textNode, editor.textLength); 253 aTest.func(staticBefore.textNode, staticBefore.textLength); 254 assert_equals(document.activeElement, editor.element); 255 assert_equals(document.documentElement.scrollTop, 0); 256 }, "Active element should be 'editor' after " + aTest.doingDescription + " with end of the first text node of 'staticBefore' (before the collapsed selection) when active element is 'editor'"); 257 test(function() { 258 resetFocusAndSelectionRange(outerEditor); 259 document.getSelection().collapse(outerEditor.textNode, outerEditor.textLength); 260 aTest.func(editor.textNode, editor.textLength); 261 assert_equals(document.activeElement, outerEditor.element); 262 assert_equals(document.documentElement.scrollTop, 0); 263 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'editor' (before the collapsed selection) when active element is 'outerEditor'"); 264 test(function() { 265 resetFocusAndSelectionRange(innerEditor); 266 document.getSelection().collapse(innerEditor.textNode, innerEditor.textLength); 267 aTest.func(outerEditor.textNode, outerEditor.textLength); 268 assert_equals(document.activeElement, outerEditor.element); 269 assert_equals(document.documentElement.scrollTop, 0); 270 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'outerEditor' (before the collapsed selection) when active element is 'innerEditor'"); 271 test(function() { 272 resetFocusAndSelectionRange(innerEditor); 273 document.getSelection().collapse(innerEditor.textNode, innerEditor.textLength); 274 aTest.func(staticInEditor.textNode, staticInEditor.textLength); 275 assert_equals(document.activeElement, innerEditor.element); 276 assert_equals(document.documentElement.scrollTop, 0); 277 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticInEditor' (before the collapsed selection) when active element is 'innerEditor'"); 278 279 test(function() { 280 resetFocusAndSelectionRange(editor); 281 document.getSelection().selectAllChildren(editor.textNode); 282 aTest.func(staticBefore.textNode, staticBefore.textLength); 283 assert_equals(document.activeElement, editor.element); 284 assert_equals(document.documentElement.scrollTop, 0); 285 }, "Active element should be 'editor' after " + aTest.doingDescription + " with end of the first text node of 'staticBefore' (before the selection) when active element is 'editor'"); 286 test(function() { 287 resetFocusAndSelectionRange(outerEditor); 288 document.getSelection().selectAllChildren(outerEditor.textNode); 289 aTest.func(editor.textNode, editor.textLength); 290 assert_equals(document.activeElement, outerEditor.element); 291 assert_equals(document.documentElement.scrollTop, 0); 292 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'editor' (before the selection) when active element is 'outerEditor'"); 293 test(function() { 294 resetFocusAndSelectionRange(innerEditor); 295 document.getSelection().selectAllChildren(innerEditor.textNode); 296 aTest.func(outerEditor.textNode, outerEditor.textLength); 297 assert_equals(document.activeElement, outerEditor.element); 298 assert_equals(document.documentElement.scrollTop, 0); 299 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with end of the first text node of 'outerEditor' (before the selection) when active element is 'innerEditor'"); 300 test(function() { 301 resetFocusAndSelectionRange(innerEditor); 302 document.getSelection().selectAllChildren(innerEditor.textNode); 303 aTest.func(staticInEditor.textNode, staticInEditor.textLength); 304 assert_equals(document.activeElement, innerEditor.element); 305 assert_equals(document.documentElement.scrollTop, 0); 306 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with end of the first text node of 'staticInEditor' (before the selection) when active element is 'innerEditor'"); 307 }); 308 309 // Range.setStart*() should move focus to an editing host when the range is shrunken into it. 310 [{ func: setStart, doingDescription: "Range.setStart()" }, 311 { func: setStartBefore, doingDescription: "Range.setStartBefore()" }].forEach((aTest, aIndex, aArray)=>{ 312 test(function() { 313 resetFocusAndSelectionRange(); 314 document.getSelection().setBaseAndExtent(staticBefore.textNode, 0, 315 editor.textNode, editor.textLength); 316 aTest.func(editor.textNode, 0); 317 assert_equals(document.activeElement, editor.element); 318 assert_equals(document.documentElement.scrollTop, 0); 319 }, "Active element should be 'editor' after " + aTest.doingDescription + " with start of the first text node of 'editor' (shrunken into 'editor') when active element is the <body>"); 320 test(function() { 321 resetFocusAndSelectionRange(editor); 322 document.getSelection().setBaseAndExtent(editor.textNode, 0, 323 outerEditor.textNode, outerEditor.textLength); 324 aTest.func(outerEditor.textNode, 0); 325 assert_equals(document.activeElement, outerEditor.element); 326 assert_equals(document.documentElement.scrollTop, 0); 327 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with start of the first text node of 'outerEditor' (shrunken into 'outerEditor') when active element is 'editor'"); 328 test(function() { 329 resetFocusAndSelectionRange(outerEditor); 330 document.getSelection().setBaseAndExtent(outerEditor.textNode, 0, 331 staticInEditor.textNode, staticInEditor.textLength); 332 aTest.func(staticInEditor.textNode, 0); 333 assert_equals(document.activeElement, outerEditor.element); 334 assert_equals(document.documentElement.scrollTop, 0); 335 }, "Active element should be 'outerEditor' after " + aTest.doingDescription + " with start of the first text node of 'staticInEditor' (shrunken into 'staticInEditor') when active element is 'outerEditor'"); 336 test(function() { 337 resetFocusAndSelectionRange(outerEditor); 338 document.getSelection().setBaseAndExtent(outerEditor.textNode, 0, 339 innerEditor.textNode, innerEditor.textLength); 340 aTest.func(innerEditor.textNode, 0); 341 assert_equals(document.activeElement, innerEditor.element); 342 assert_equals(document.documentElement.scrollTop, 0); 343 }, "Active element should be 'innerEditor' after " + aTest.doingDescription + " with start of the first text node of 'innerEditor' (shrunken into 'innerEditor') when active element is 'outerEditor'"); 344 test(function() { 345 resetFocusAndSelectionRange(); 346 document.getSelection().setBaseAndExtent(innerEditor.textNode, 0, 347 anchor.textNode, anchor.textLength); 348 aTest.func(anchor.textNode, 0); 349 assert_equals(document.activeElement, document.body); 350 assert_equals(document.documentElement.scrollTop, 0); 351 }, "Active element should be the <body> after " + aTest.doingDescription + " with start of the first text node of 'anchor' (shrunken into 'anchor') when active element is the <body>"); 352 }); 353 </script>