test_user_select.html (11529B)
1 <!DOCTYPE> 2 <html> 3 <head> 4 <title>user-select selection tests</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script src="/tests/SimpleTest/EventUtils.js"></script> 7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 8 9 <style type="text/css"> 10 @font-face { 11 font-family: Ahem; 12 src: url("Ahem.ttf"); 13 } 14 body { font-family: Ahem; font-size: 20px; } 15 s, .non-selectable { user-select: none; } 16 n { display: none; } 17 a { position:absolute; bottom: 0; right:0; } 18 .text { user-select: text; } 19 </style> 20 21 </head> 22 <body> 23 24 <div id="test1">aaaaaaa<s>bbbbbbbb</s>ccccccc</div> 25 <div id="test2"><s>aaaaaaa</s>bbbbbbbbccccccc</div> 26 <div id="test3">aaaaaaabbbbbbbb<s>ccccccc</s></div> 27 <div id="test4">aaaaaaa<x><s>bbbbbbbb</s></x>ccccccc</div> 28 <div id="test5"><x><s>aaaaaaa</s></x>bbbbbbbbccccccc</div> 29 <div id="test6">aaaaaaabbbbbbbb<x><s>ccccccc</s></x></div> 30 <div id="test7">aaaaaaa<x><s><n>bbbb</n>bbbb</s></x>ccccccc</div> 31 <div id="test8"><x><s>aa<n>aaa</n>aa</s></x>bbbbbbbbccccccc</div> 32 <div id="test9">aaaaaaabbbbbbbb<x><s>cc<n>ccccc</n></s></x></div> 33 <div id="testA">aaaaaaa<n>bbb<s>bbbbb</s></n>ccccccc</div> 34 <div id="testB"><n><s>aaaa</s>aaa</n>bbbbbbbbccccccc</div> 35 <div id="testC">aaaaaaabbbbbbbb<n>cc<s>c</s>cccc</n></div> 36 <div id="testE">aaa<s id="testEc1">aaaa<a class="text">bbbb</a>dd<a>cccc</a>ddddddd</s>eeee</div> 37 <div id="testI">aaa<span contenteditable="true" spellcheck="false">bbb</span><s>ccc</s>ddd</div> 38 <div id="testF">aaaa 39 <div class="non-selectable">x</div> 40 <div class="non-selectable">x</div> 41 <div class="non-selectable">x</div> 42 bbbb</div> 43 <div id="testG" style="white-space:pre">aaaa 44 <div class="non-selectable">x</div> 45 <div class="non-selectable">x</div> 46 <div class="non-selectable">x</div> 47 bbbb</div> 48 <div id="testH" style="white-space:pre">aaaa 49 <div class="non-selectable">x</div><input> 50 bbbbbbb</div> 51 52 <iframe id="testD" srcdoc="<body>aaaa<span style='user-select:none'>bbbb</span>cccc"></iframe> 53 54 <pre id="test"> 55 <script class="testbody" type="text/javascript"> 56 57 function test() 58 { 59 const excludeNonSelectableNodes = SpecialPowers.getBoolPref("dom.selection.exclude_non_selectable_nodes"); 60 61 function clear(w) 62 { 63 var sel = (w ? w : window).getSelection(); 64 sel.removeAllRanges(); 65 } 66 function doneTest(e) 67 { 68 // We hide the elements we're done with so that later tests 69 // are inside the rather narrow iframe mochitest gives us. 70 // It matters for synthesizeMouse event tests. 71 e.style.display = 'none'; 72 e.offsetHeight; 73 } 74 75 function dragSelect(e, x1, x2, x3) 76 { 77 dir = x2 > x1 ? 1 : -1; 78 synthesizeMouse(e, x1, 5, { type: "mousedown" }); 79 synthesizeMouse(e, x1 + dir, 5, { type: "mousemove" }); 80 if (x3) 81 synthesizeMouse(e, x3, 5, { type: "mousemove" }); 82 synthesizeMouse(e, x2 - dir, 5, { type: "mousemove" }); 83 synthesizeMouse(e, x2, 5, { type: "mouseup" }); 84 } 85 86 function shiftClick(e, x) 87 { 88 synthesizeMouse(e, x, 5, { type: "mousedown", shiftKey: true }); 89 synthesizeMouse(e, x, 5, { type: "mouseup", shiftKey: true }); 90 } 91 92 function init(arr, e) 93 { 94 clear(); 95 var sel = window.getSelection(); 96 for (i = 0; i < arr.length; ++i) { 97 var data = arr[i]; 98 var r = new Range() 99 r.setStart(node(e, data[0]), data[1]); 100 r.setEnd(node(e, data[2]), data[3]); 101 sel.addRange(r); 102 } 103 } 104 105 function NL(s) { return s.replace(/(\r\n|\n\r|\r)/g, '\n'); } 106 107 function checkText(text, e) 108 { 109 var sel = window.getSelection(); 110 is(NL(sel.toString()), text, e.id + ": selected text") 111 } 112 113 function checkRangeText(text, index) 114 { 115 var r = window.getSelection().getRangeAt(index); 116 is(NL(r.toString()), text, e.id + ": range["+index+"].toString()") 117 } 118 119 function node(e, arg) 120 { 121 if (typeof arg == "number") 122 return arg == -1 ? e : e.childNodes[arg]; 123 return arg; 124 } 125 126 function checkRangeCount(n, e) 127 { 128 var sel = window.getSelection(); 129 is(sel.rangeCount, n, e.id + ": Selection range count"); 130 } 131 132 function checkRange(i, expected, e) { 133 var sel = window.getSelection(); 134 var r = sel.getRangeAt(i); 135 is(r.startContainer, node(e, expected[0]), e.id + ": range["+i+"].startContainer"); 136 is(r.startOffset, expected[1], e.id + ": range["+i+"].startOffset"); 137 is(r.endContainer, node(e, expected[2]), e.id + ": range["+i+"].endContainer"); 138 is(r.endOffset, expected[3], e.id + ": range["+i+"].endOffset"); 139 } 140 141 function checkRanges(arr, e) 142 { 143 checkRangeCount(arr.length, e); 144 for (i = 0; i < arr.length; ++i) { 145 var expected = arr[i]; 146 checkRange(i, expected, e); 147 } 148 } 149 150 // ====================================================== 151 // ================== dragSelect tests ================== 152 // ====================================================== 153 154 var e = document.getElementById('test1'); 155 dragSelect(e, 20, 340); 156 checkText('aaaaaacc', e); 157 checkRanges( 158 excludeNonSelectableNodes ? [[0,1,-1,1], [2,0,2,2]] : [[0,1,2,2]], 159 e 160 ); 161 162 clear(); 163 dragSelect(e, 20, 260, 120); 164 checkText('aaaaa', e); 165 checkRanges([[0,1,0,6]], e); 166 doneTest(e); 167 168 clear(); 169 e = document.getElementById('test2'); 170 dragSelect(e, 20, 340); 171 checkText('', e); 172 checkRanges([], e); 173 174 clear(); 175 dragSelect(e, 340, 20, 141); 176 checkText('bbbbbbbbcc', e); 177 checkRanges([[1,0,1,10]], e); 178 // #test2 is used again below 179 180 clear(); 181 e = document.getElementById('test3'); 182 dragSelect(e, 20, 340, 295); 183 checkText('aaaaaabbbbbbbb', e); 184 checkRanges([[0,1,0,15]], e); 185 // #test3 is used again below 186 187 clear(); 188 e = document.getElementById('test4'); 189 dragSelect(e, 20, 340); 190 checkText('aaaaaacc', e); 191 checkRanges( 192 excludeNonSelectableNodes ? [[0,1,1,0], [2,0,2,2]] : [[0,1,2,2]], 193 e 194 ); 195 doneTest(e); 196 197 clear(); 198 e = document.getElementById('test5'); 199 dragSelect(e, 340, 20, 141); 200 checkText('bbbbbbbbcc', e); 201 checkRanges([[1,0,1,10]], e); 202 doneTest(e); 203 204 clear(); 205 e = document.getElementById('test6'); 206 dragSelect(e, 20, 340, 295); 207 checkText('aaaaaabbbbbbbb', e); 208 checkRanges([[0,1,0,15]], e); 209 doneTest(e); 210 211 clear(); 212 e = document.getElementById('test7'); 213 dragSelect(e, 20, 340); 214 checkText('aaaaaacccccc', e); 215 checkRanges( 216 excludeNonSelectableNodes ? [[0,1,1,0], [2,0,2,6]] : [[0,1,2,6]], 217 e 218 ); 219 doneTest(e); 220 221 clear(); 222 e = document.getElementById('test8'); 223 dragSelect(e, 340, 20, 140); 224 checkText('bbbbbccccc', e); 225 checkRanges([[1,3,1,13]], e); 226 doneTest(e); 227 228 clear(); 229 e = document.getElementById('test9'); 230 dragSelect(e, 20, 340, 295); 231 checkText('aaaaaabbbbbbbb', e); 232 checkRanges([[0,1,0,15]], e); 233 doneTest(e); 234 235 clear(); 236 e = document.getElementById('testA'); 237 dragSelect(e, 20, 340); 238 checkText('aaaaaaccccccc', e); 239 checkRanges([[0,1,2,7]], e); 240 checkRangeText('aaaaaabbbbbbbbccccccc', 0); 241 doneTest(e); 242 243 clear(); 244 e = document.getElementById('testB'); 245 dragSelect(e, 340, 20, 140); 246 checkText('bbbbbbbccccccc', e); 247 checkRanges([[1,1,1,15]], e); 248 doneTest(e); 249 250 clear(); 251 e = document.getElementById('testE'); 252 dragSelect(e, 20, 360, 295); 253 checkText('aa\nbbbb\nee', e); 254 if (excludeNonSelectableNodes) { 255 checkRangeCount(3, e); 256 checkRange(0, [0,1,-1,1], e); 257 checkRange(1, [1,0,-1,2], e.children[0]); 258 checkRange(2, [2,0,2,2], e); 259 } else { 260 checkRangeCount(1, e); 261 checkRanges([[0,1,2,2]], e); 262 } 263 doneTest(e); 264 265 clear(); 266 e = document.getElementById('testI'); 267 dragSelect(e, 200, 80); 268 checkText('bbd', e); 269 checkRangeCount(excludeNonSelectableNodes ? 2 : 1, e); 270 doneTest(e); 271 272 // ====================================================== 273 // ================== shift+click tests ================= 274 // ====================================================== 275 276 // test extending a selection that starts in a -moz-user-select:none node 277 clear(); 278 e = document.getElementById('test2'); 279 init([[0,0,0,1]], e); 280 checkRangeText('aaaaaaa', 0); 281 checkText('', e); 282 shiftClick(e, 340); 283 checkText('bbbbbbbbcc', e); 284 if (excludeNonSelectableNodes) { 285 checkRangeText('bbbbbbbbcc', 0); 286 checkRanges([[-1,1,1,10]], e); 287 } else { 288 checkRangeText('aaaaaaabbbbbbbbcc', 0); 289 checkRanges([[0,0,1,10]], e); 290 } 291 doneTest(e); 292 293 // test extending a selection that end in a -moz-user-select:none node 294 clear(); 295 e = document.getElementById('test3'); 296 init([[1,0,1,1]], e); 297 checkRangeText('ccccccc', 0); 298 checkText('', e); 299 shiftClick(e, 20); 300 checkRangeText('aaaaaabbbbbbbb', 0); 301 checkText('aaaaaabbbbbbbb', e); 302 checkRanges( 303 excludeNonSelectableNodes ? [[0,1,-1,1]] : [[0,1,1,0]], 304 e 305 ); 306 doneTest(e); 307 308 clear(); 309 e = document.getElementById('testF'); 310 synthesizeMouse(e, 1, 1, {}); 311 synthesizeMouse(e, 400, 100, { shiftKey: true }); 312 checkText("aaaa bbbb", e); 313 checkRanges( 314 excludeNonSelectableNodes ? [[0,0,-1,1],[6,0,6,5]] : [[0,0,6,5]], 315 e 316 ); 317 doneTest(e); 318 319 clear(); 320 e = document.getElementById('testG'); 321 synthesizeMouse(e, 1, 1, {}); 322 synthesizeMouse(e, 400, 180, { shiftKey: true }); 323 checkText("aaaa\n\n\n\nbbbb", e); 324 checkRanges( 325 excludeNonSelectableNodes ? [[0,0,-1,1],[2,0,-1,3],[4,0,-1,5],[6,0,6,5]] : [[0,0,6,5]], 326 e 327 ); 328 doneTest(e); 329 330 clear(); 331 e = document.getElementById('testH'); 332 synthesizeMouse(e, 1, 1, {}); 333 synthesizeMouse(e, 30, 90, { shiftKey: true }); 334 synthesizeMouse(e, 50, 90, { shiftKey: true }); 335 synthesizeMouse(e, 70, 90, { shiftKey: true }); 336 checkText("aaaa\n\nbbb", e); 337 checkRanges( 338 excludeNonSelectableNodes ? [[0,0,-1,1],[-1,2,3,4]] : [[0,0,3,4]], 339 e 340 ); 341 342 doneTest(e); 343 // ====================================================== 344 // ==================== Script tests ==================== 345 // ====================================================== 346 347 clear(); 348 e = document.getElementById('testD'); 349 clear(e.contentWindow); 350 sel = e.contentWindow.getSelection(); 351 sel.selectAllChildren(e.contentDocument.body); 352 is(window.getSelection().rangeCount, 0, "testD: no selection in outer window"); 353 is(sel.toString(), 'aaaacccc', "testD: scripted selection"); 354 is(sel.rangeCount, 1, "testD: scripted selection isn't filtered"); 355 is(sel.getRangeAt(0).toString(), 'aaaabbbbcccc', "testD: scripted selection isn't filtered"); 356 357 // ====================================================== 358 // ================== Kbd command tests ================= 359 // ====================================================== 360 361 clear(); 362 e = document.getElementById('testD'); 363 clear(e.contentWindow); 364 e.contentWindow.focus(); 365 synthesizeKey("a", { accelKey:true }, e.contentWindow); 366 sel = e.contentWindow.getSelection(); 367 is(window.getSelection().rangeCount, 0, "testD: no selection in outer window"); 368 is(sel.toString(), 'aaaacccc', "testD: kbd selection"); 369 if (excludeNonSelectableNodes) { 370 is(sel.rangeCount, 2, "testD: kbd selection is filtered"); 371 is(sel.getRangeAt(0).toString(), 'aaaa', "testD: kbd selection is filtered"); 372 is(sel.getRangeAt(1).toString(), 'cccc', "testD: kbd selection is filtered"); 373 } else { 374 is(sel.rangeCount, 1, "testD: kbd selection is filtered"); 375 is(sel.getRangeAt(0).toString(), 'aaaabbbbcccc', "testD: kbd selection is filtered"); 376 } 377 doneTest(e); 378 379 clear(); 380 SimpleTest.finish(); 381 } 382 383 // These tests depends on the Ahem font being loaded and rendered so wait for 384 // font to load, then wait a frame for them to be rendered too. 385 window.onload = function() { 386 document.fonts.ready.then(function() { 387 requestAnimationFrame(test); 388 }); 389 }; 390 391 SimpleTest.waitForExplicitFinish(); 392 </script> 393 </pre> 394 </body> 395 </html>