test_dragstart.html (32263B)
1 <html> 2 <head> 3 <title>Tests for the dragstart event</title> 4 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script src="/tests/SimpleTest/EventUtils.js"></script> 7 8 <!-- 9 This test checks the dragstart event and the DataTransfer object 10 --> 11 12 <script> 13 14 SimpleTest.waitForExplicitFinish(); 15 16 var gDragInfo; 17 var gDataTransfer = null; 18 var gExtraDragTests = 0; 19 var gIsMac = navigator.platform.includes("Mac"); 20 21 function runTests() 22 { 23 // first, create a selection and try dragging it 24 var draggable = $("draggable"); 25 window.getSelection().selectAllChildren(draggable); 26 synthesizeMouse(draggable, 6, 6, { type: "mousedown" }); 27 synthesizeMouse(draggable, 14, 14, { type: "mousemove" }); 28 // drags are asynchronous on Linux, so this extra event is needed to make 29 // sure the drag gets processed 30 synthesizeMouse(draggable, 15, 15, { type: "mousemove" }); 31 } 32 33 function afterDragTests() 34 { 35 // the dragstart should have occurred due to moving the mouse. gDataTransfer 36 // caches the dataTransfer that was used, however it should now be empty and 37 // be read only. 38 ok(gDataTransfer instanceof DataTransfer, "DataTransfer after dragstart event"); 39 checkTypes(gDataTransfer, [], 0, "after dragstart event"); 40 41 expectError(() => gDataTransfer.setData("text/plain", "Some Text"), 42 "NoModificationAllowedError", "setData when read only"); 43 expectError(() => gDataTransfer.clearData("text/plain"), 44 "NoModificationAllowedError", "clearData when read only"); 45 expectError(() => gDataTransfer.addElement(draggable), 46 "NoModificationAllowedError", "addElement when read only"); 47 48 var evt = document.createEvent("dragevent"); 49 ok(evt instanceof DragEvent, "synthetic dragevent class") 50 ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent") 51 evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15, 52 false, true, false, false, 0, null, null); 53 $("synthetic").dispatchEvent(evt); 54 55 var evt = document.createEvent("dragevent"); 56 ok(evt instanceof DragEvent, "synthetic dragevent class") 57 evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15, 58 true, false, true, true, 2, document.documentElement, null); 59 $("synthetic2").dispatchEvent(evt); 60 61 // next, dragging links and images 62 sendMouseEventsForDrag("link"); 63 sendMouseEventsForDrag("image"); 64 65 // disable testing input dragging for now, as it doesn't seem to be testable 66 // draggable = $("input"); 67 // draggable.setSelectionRange(0, 4); 68 // synthesizeMouse(draggable, 8, 8, { type: "mousedown" }); 69 // synthesizeMouse(draggable, 15, 15, { type: "mousemove" }); 70 // sendMouseEventsForDrag("input"); 71 72 // draggable elements inside a shadow root 73 sendMouseEventsForShadowRootDrag("shadow_host_containing_draggable"); 74 sendMouseEventsForShadowRootDrag("shadow_host_containing_image"); 75 76 // next, check if the draggable attribute can be used to adjust the drag target 77 gDragInfo = { target: $("dragtrue"), testid: "draggable true node" }; 78 sendMouseEventsForDrag("dragtrue"); 79 gDragInfo = { target: $("dragtrue"), testid: "draggable true child" }; 80 sendMouseEventsForDrag("spantrue"); 81 82 gDragInfo = { target: $("dragfalse").firstChild, testid: "draggable false node" }; 83 sendMouseEventsForDrag("dragfalse"); 84 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 85 86 gDragInfo = { target: $("spanfalse").firstChild, testid: "draggable false child" }; 87 sendMouseEventsForDrag("spanfalse"); 88 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 89 90 gDragInfo = { target: $("userselectnone").firstChild, testid: "user select none inside draggable false node" }; 91 sendMouseEventsForDrag("userselectnone"); 92 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 93 94 gDragInfo = { target: $("draggable_with_undraggable_descendant"), testid: "undraggable inside draggable" }; 95 sendMouseEventsForDrag("undraggable_inside_draggable"); 96 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 97 98 sendMouseEventsForDrag("link_to_file"); 99 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 100 101 sendMouseEventsForDrag("broken_file_image"); 102 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 103 104 if (navigator.platform.startsWith("Win")) { 105 sendMouseEventsForDrag("link_to_windows_file"); 106 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 107 108 sendMouseEventsForDrag("broken_windows_file_image"); 109 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 110 111 sendMouseEventsForDrag("link_to_backslash_windows_file"); 112 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 113 114 sendMouseEventsForDrag("broken_backslash_windows_file_image"); 115 synthesizeMouse(draggable, 12, 12, { type: "mouseup" }); 116 } 117 118 if (gExtraDragTests == 7) 119 SimpleTest.finish(); 120 } 121 122 function sendMouseEventsForDrag(nodeid) 123 { 124 info("Sending events for " + nodeid); 125 var draggable = $(nodeid); 126 synthesizeMouse(draggable, 3, 3, { type: "mousedown" }); 127 synthesizeMouse(draggable, 10, 10, { type: "mousemove" }); 128 synthesizeMouse(draggable, 12, 12, { type: "mousemove" }); 129 } 130 function sendMouseEventsForShadowRootDrag(host) 131 { 132 var draggable = $(host).shadowRoot.firstElementChild; 133 synthesizeMouse(draggable, 3, 3, { type: "mousedown" }); 134 synthesizeMouse(draggable, 10, 10, { type: "mousemove" }); 135 synthesizeMouse(draggable, 12, 12, { type: "mousemove" }); 136 } 137 138 function doDragStartSelection(event) 139 { 140 is(event.type, "dragstart", "dragstart event type"); 141 is(event.target, $("draggable").firstChild, "dragstart event target"); 142 is(event.bubbles, true, "dragstart event bubbles"); 143 is(event.cancelable, true, "dragstart event cancelable"); 144 145 is(event.clientX, 14, "dragstart clientX"); 146 is(event.clientY, 14, "dragstart clientY"); 147 ok(event.screenX > 0, "dragstart screenX"); 148 ok(event.screenY > 0, "dragstart screenY"); 149 is(event.layerX, 14, "dragstart layerX"); 150 is(event.layerY, 14, "dragstart layerY"); 151 is(event.pageX, 14, "dragstart pageX"); 152 is(event.pageY, 14, "dragstart pageY"); 153 154 var dt = event.dataTransfer; 155 ok(dt instanceof DataTransfer, "dataTransfer is DataTransfer"); 156 gDataTransfer = dt; 157 158 var types = dt.types; 159 ok(Array.isArray(types), "initial types is an Array"); 160 checkTypes(dt, ["text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial selection"); 161 162 const includeCommonAncestor = SpecialPowers.getBoolPref( 163 "dom.serializer.includeCommonAncestor.enabled" 164 ); 165 is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain"); 166 is(dt.getData("text/html"), 167 `${includeCommonAncestor ? "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">" : ""}` + 168 `This is a <em>draggable</em> bit of text.` + 169 `${includeCommonAncestor ? "</div>" : ""}`, 170 "initial selection text/html"); 171 172 // text/plain and Text are available for compatibility. They retrieve the 173 // text/plain data. text/unicode is also for compatibility and retreives the plain text. 174 is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain"); 175 is(dt.getData("Text"), "This is a draggable bit of text.", "initial selection Text"); 176 is(dt.getData("TEXT"), "This is a draggable bit of text.", "initial selection TEXT"); 177 is(dt.getData("text/PLAIN"), "This is a draggable bit of text.", "initial selection text/PLAIN"); 178 is(dt.getData("text/unicode"), "This is a draggable bit of text.", "initial selection text/unicode"); 179 180 is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial selection item count"); 181 182 dt.clearData("text/plain"); 183 dt.clearData("text/html"); 184 dt.clearData("text/_moz_htmlinfo"); 185 dt.clearData("text/_moz_htmlcontext"); 186 187 test_DataTransfer(dt); 188 setTimeout(afterDragTests, 0); 189 } 190 191 function test_DataTransfer(dt) 192 { 193 is(SpecialPowers.wrap(dt).mozItemCount, 0, "empty itemCount"); 194 195 var types = dt.types; 196 ok(Array.isArray(types), "empty types is an Array"); 197 // The above test fails if we have SpecialPowers.wrap(dt).types instead of dt.types 198 // because dt.types will be wrapped and become a proxy. 199 // So wrap with special powers after the test 200 dt = SpecialPowers.wrap(dt); 201 checkTypes(dt, [], 0, "empty"); 202 is(dt.getData("text/plain"), "", "empty data is empty"); 203 204 // calling setDataAt requires an index that is 0 <= index <= dt.itemCount 205 expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 1), 206 "IndexSizeError", "setDataAt index too high"); 207 208 is(dt.mozUserCancelled, false, "userCancelled"); 209 210 // because an exception occurred, the data should not have been added 211 is(dt.mozItemCount, 0, "empty setDataAt index too high itemCount"); 212 dt.getData("text/plain", "", "empty setDataAt index too high getData"); 213 214 // if the type is '', do nothing, or return '' 215 dt.setData("", "Invalid Type"); 216 is(dt.types.length, 0, "invalid type setData"); 217 is(dt.getData(""), "", "invalid type getData"); 218 dt.mozSetDataAt("", "Invalid Type", 0); 219 is(dt.types.length, 0, "invalid type setDataAt"); 220 is(dt.mozGetDataAt("", 0), null, "invalid type getDataAt"); 221 222 // similar with clearDataAt and getDataAt 223 expectError(() => dt.mozGetDataAt("text/plain", 1), 224 "IndexSizeError", "getDataAt index too high"); 225 expectError(() => dt.mozClearDataAt("text/plain", 1), 226 "IndexSizeError", "clearDataAt index too high"); 227 228 dt.setData("text/plain", "Sample Text"); 229 is(dt.mozItemCount, 1, "added plaintext itemCount"); 230 checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext"); 231 232 // after all those exceptions, the data should still be the same 233 checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext after exception"); 234 235 // modifying the data associated with the format should give it the new value 236 dt.setData("text/plain", "Modified Text"); 237 is(dt.mozItemCount, 1, "modified plaintext itemCount"); 238 checkOneDataItem(dt, ["text/plain"], ["Modified Text"], 0, "modified plaintext"); 239 240 dt.setData("text/html", "<strong>Modified Text</strong>"); 241 is(dt.mozItemCount, 1, "modified html itemCount"); 242 checkOneDataItem(dt, ["text/plain", "text/html"], 243 ["Modified Text", "<strong>Modified Text</strong>"], 244 0, "modified html"); 245 246 // modifying data for a type that already exists should adjust it in place, 247 // not reinsert it at the beginning 248 dt.setData("text/plain", "New Text"); 249 is(dt.mozItemCount, 1, "modified text again itemCount"); 250 checkOneDataItem(dt, ["text/plain", "text/html"], 251 ["New Text", "<strong>Modified Text</strong>"], 252 0, "modified text again"); 253 254 var draggable = $("draggable"); 255 dt.setData("application/-moz-node", draggable); 256 checkOneDataItem(dt, ["text/plain", "text/html", "application/-moz-node"], 257 ["New Text", "<strong>Modified Text</strong>", draggable.toString()], 258 0, "added node"); 259 260 dt.clearData(""); // null means clear all 261 is(dt.mozItemCount, 0, "itemCount after clearData empty string"); 262 checkTypes(dt, [], 0, "empty after clearData empty string"); 263 264 dt.setData("text/plain", 22); 265 dt.setData("text/html", 5.6); 266 dt.setData("text/xml", 5.6); 267 checkTypes(dt, ["text/plain", "text/html", "text/xml"], ["22", "5.6", ""], 0, "add numeric and empty data"); 268 269 dt.clearData(); // no argument means clear all 270 is(dt.mozItemCount, 0, "itemCount after clearData no argument"); 271 checkTypes(dt, [], 0, "empty after clearData no argument"); 272 273 // check 'Text' type which should convert into text/plain 274 dt.setData("Text", "Sample Text"); 275 checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "set Text"); 276 is(dt.getData("Text"), "Sample Text", "getData Text"); 277 is(dt.mozGetDataAt("Text", 0), "Sample Text", "getDataAt Text"); 278 dt.setData("text/plain", "More Text"); 279 checkOneDataItem(dt, ["text/plain"], ["More Text"], 0, "set text/plain after set Text"); 280 281 dt.mozClearDataAt("", 0); // null means clear all 282 is(dt.mozItemCount, 0, "itemCount after clearDataAt empty string"); 283 checkTypes(dt, [], 0, "empty after clearDataAt empty string"); 284 285 // check text/uri-list type 286 dt.setData("text/uri-list", "http://www.mozilla.org"); 287 checkURL(dt, "http://www.mozilla.org", "http://www.mozilla.org", 0, "set text/uri-list"); 288 289 // check URL type which should add text/uri-list data 290 dt.setData("URL", "ftp://ftp.example.com"); 291 checkURL(dt, "ftp://ftp.example.com", "ftp://ftp.example.com", 0, "set URL"); 292 checkTypes(dt, ["text/uri-list"], ["ftp://ftp.example.com"], "url types"); 293 294 // clearing text/uri-list data 295 dt.clearData("text/uri-list"); 296 is(dt.mozItemCount, 0, "itemCount after clear url-list"); 297 is(dt.getData("text/uri-list"), "", "text/uri-list after clear url-list"); 298 is(dt.getData("URL"), "", "URL after clear url-list"); 299 300 // check text/uri-list parsing 301 dt.setData("text/uri-list", "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com"); 302 checkURL(dt, "http://www.xulplanet.com", 303 "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com", 304 0, "uri-list 3 lines"); 305 306 dt.setData("text/uri-list", "#http://www.mozilla.org"); 307 is(dt.getData("URL"), "", "uri-list commented"); 308 dt.setData("text/uri-list", "#http://www.mozilla.org\n"); 309 is(dt.getData("URL"), "", "uri-list commented with newline"); 310 311 // check that clearing the URL type also clears the text/uri-list type 312 dt.clearData("URL"); 313 is(dt.getData("text/uri-list"), "", "clear URL"); 314 315 dt.setData("text/uri-list", "#http://www.mozilla.org\n\n\n\n\n"); 316 is(dt.getData("URL"), "", "uri-list with blank lines"); 317 dt.setData("text/uri-list", ""); 318 is(dt.getData("URL"), "", "empty uri-list"); 319 dt.setData("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n"); 320 is(dt.getData("URL"), "http://www.xulplanet.com", "uri-list mix"); 321 dt.setData("text/uri-list", "\nhttp://www.mozilla.org"); 322 is(dt.getData("URL"), "", "empty line to start uri-list"); 323 dt.setData("text/uri-list", " http://www.mozilla.org#anchor "); 324 is(dt.getData("URL"), "http://www.mozilla.org#anchor", "uri-list with spaces and hash"); 325 326 // ensure that setDataAt works the same way 327 dt.mozSetDataAt("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n", 0); 328 checkURL(dt, "http://www.xulplanet.com", 329 "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com \r\n", 330 0, "uri-list mix setDataAt"); 331 332 // now test adding multiple items to be dragged using the setDataAt method 333 dt.clearData(); 334 dt.mozSetDataAt("text/plain", "First Item", 0); 335 dt.mozSetDataAt("text/plain", "Second Item", 1); 336 expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 3), 337 "IndexSizeError", "setDataAt index too high with two items"); 338 is(dt.mozItemCount, 2, "setDataAt item itemCount"); 339 checkOneDataItem(dt, ["text/plain"], ["First Item"], 0, "setDataAt item at index 0"); 340 checkOneDataItem(dt, ["text/plain"], ["Second Item"], 1, "setDataAt item at index 1"); 341 342 dt.mozSetDataAt("text/html", "<em>First Item</em>", 0); 343 dt.mozSetDataAt("text/html", "<em>Second Item</em>", 1); 344 is(dt.mozItemCount, 2, "setDataAt two types item itemCount"); 345 checkOneDataItem(dt, ["text/plain", "text/html"], 346 ["First Item", "<em>First Item</em>"], 0, "setDataAt two types item at index 0"); 347 checkOneDataItem(dt, ["text/plain", "text/html"], 348 ["Second Item", "<em>Second Item</em>"], 1, "setDataAt two types item at index 1"); 349 350 dt.mozSetDataAt("text/html", "<em>Changed First Item</em>", 0); 351 dt.mozSetDataAt("text/plain", "Changed Second Item", 1); 352 is(dt.mozItemCount, 2, "changed with setDataAt item itemCount"); 353 checkOneDataItem(dt, ["text/plain", "text/html"], 354 ["First Item", "<em>Changed First Item</em>"], 0, "changed with setDataAt item at index 0"); 355 checkOneDataItem(dt, ["text/plain", "text/html"], 356 ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setDataAt item at index 1"); 357 358 dt.setData("text/html", "Changed with setData"); 359 is(dt.mozItemCount, 2, "changed with setData"); 360 checkOneDataItem(dt, ["text/plain", "text/html"], 361 ["First Item", "Changed with setData"], 0, "changed with setData item at index 0"); 362 checkOneDataItem(dt, ["text/plain", "text/html"], 363 ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setData item at index 1"); 364 365 dt.mozSetDataAt("application/-moz-node", "draggable", 2); 366 is(dt.mozItemCount, 3, "setDataAt node itemCount"); 367 checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2"); 368 369 // Try to add and then remove a non-string type to the DataTransfer and ensure 370 // that the type appears in DataTransfer.types. 371 { 372 dt.mozSetDataAt("application/-x-body", document.body, 0); 373 let found = false; 374 for (let i = 0; i < dt.types.length; ++i) { 375 if (dt.types[i] == "application/-x-body") { 376 found = true; 377 break; 378 } 379 } 380 ok(found, "Data should appear in datatransfer.types despite having a non-string type"); 381 dt.mozClearDataAt("application/-x-body", 0); 382 } 383 384 dt.mozClearDataAt("text/html", 1); 385 is(dt.mozItemCount, 3, "clearDataAt itemCount"); 386 checkOneDataItem(dt, ["text/plain", "text/html"], 387 ["First Item", "Changed with setData"], 0, "clearDataAt item at index 0"); 388 checkOneDataItem(dt, ["text/plain"], ["Changed Second Item"], 1, "clearDataAt item at index 1"); 389 390 dt.mozClearDataAt("text/plain", 1); 391 is(dt.mozItemCount, 2, "clearDataAt last type itemCount"); 392 checkOneDataItem(dt, ["text/plain", "text/html"], 393 ["First Item", "Changed with setData"], 0, "clearDataAt last type at index 0"); 394 checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 1, "clearDataAt last type item at index 2"); 395 expectError(() => dt.mozGetDataAt("text/plain", 2), 396 "IndexSizeError", "getDataAt after item removed index too high"); 397 398 dt.mozSetDataAt("text/unknown", "Unknown type", 2); 399 dt.mozSetDataAt("text/unknown", "Unknown type", 1); 400 is(dt.mozItemCount, 3, "add unknown type"); 401 checkOneDataItem(dt, ["application/-moz-node", "text/unknown"], 402 ["draggable", "Unknown type"], 1, "add unknown type item at index 1"); 403 checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 2, "add unknown type item at index 2"); 404 405 dt.mozClearDataAt("", 1); 406 is(dt.mozItemCount, 2, "clearDataAt empty string"); 407 checkOneDataItem(dt, ["text/plain", "text/html"], 408 ["First Item", "Changed with setData"], 0, "clearDataAt empty string item at index 0"); 409 checkOneDataItem(dt, ["text/unknown"], 410 ["Unknown type"], 1, "clearDataAt empty string item at index 1"); 411 412 // passing a format that doesn't exist to clearData or clearDataAt should just 413 // do nothing 414 dt.clearData("text/something"); 415 dt.mozClearDataAt("text/something", 1); 416 is(dt.mozItemCount, 2, "clearData type that does not exist"); 417 checkOneDataItem(dt, ["text/plain", "text/html"], 418 ["First Item", "Changed with setData"], 0, "clearData type that does not exist item at index 0"); 419 checkOneDataItem(dt, ["text/unknown"], 420 ["Unknown type"], 1, "clearData type that does not exist item at index 1"); 421 422 expectError(() => dt.mozClearDataAt("text/plain", 3), 423 "IndexSizeError", "clearData index too high with two items"); 424 425 // ensure that clearData() removes all data associated with the first item, but doesn't 426 // shift the second item down into the first item's slot. 427 dt.clearData(); 428 is(dt.mozItemCount, 2, "clearData no argument with multiple items itemCount"); 429 checkOneDataItem(dt, [], [], 0, 430 "clearData no argument with multiple items item at index 0"); 431 checkOneDataItem(dt, ["text/unknown"], 432 ["Unknown type"], 1, "clearData no argument with multiple items item at index 1"); 433 434 // remove tha remaining data in index 1. As index 0 is empty at this point, this will actually 435 // drop mozItemCount to 0. (XXX: This is because of spec-compliance reasons related 436 // to the more-recent dt.item API. It's an unfortunate, but hopefully rare edge case) 437 dt.mozClearDataAt("", 1); 438 is(dt.mozItemCount, 0, "all data cleared"); 439 440 // now check the effectAllowed and dropEffect properties 441 is(dt.dropEffect, "none", "initial dropEffect"); 442 is(dt.effectAllowed, "uninitialized", "initial effectAllowed"); 443 444 ["copy", "none", "link", "", "other", "copyMove", "all", "uninitialized", "move"].forEach( 445 function (i) { 446 dt.dropEffect = i; 447 is(dt.dropEffect, i == "" || i == "other" || i == "copyMove" || 448 i == "all" || i == "uninitialized" ? "link" : i, 449 "dropEffect set to " + i); 450 is(dt.effectAllowed, "uninitialized", "effectAllowed not modified by dropEffect set to " + i); 451 } 452 ); 453 454 ["move", "copy", "link", "", "other", "moveCopy", "copyMove", 455 "linkMove", "copyLink", "all", "uninitialized", "none"].forEach( 456 function (i) { 457 dt.effectAllowed = i; 458 is(dt.dropEffect, "move", "dropEffect not modified by effectAllowed set to " + i); 459 is(dt.effectAllowed, i == "" || i == "other" || i == "moveCopy" ? "link" : i, 460 "effectAllowed set to " + i); 461 } 462 ); 463 } 464 465 function doDragStartLink(event) 466 { 467 var dt = event.dataTransfer; 468 checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list", 469 "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial link"); 470 471 is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial link item count"); 472 is(dt.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list"); 473 is(dt.getData("text/plain"), "http://www.mozilla.org/", "link text/plain"); 474 475 event.preventDefault(); 476 477 gExtraDragTests++; 478 } 479 480 function doDragStartImage(event) 481 { 482 var dataurl = $("image").src; 483 484 var dt = event.dataTransfer; 485 checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list", 486 "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain", 487 "application/x-moz-nativeimage", "application/x-moz-file-promise", 488 "application/x-moz-file-promise-url", "application/x-moz-file-promise-dest-filename"], 489 0, "initial image"); 490 491 is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial image item count"); 492 is(dt.getData("text/uri-list"), dataurl, "image text/uri-list"); 493 is(dt.getData("text/plain"), dataurl, "image text/plain"); 494 495 event.preventDefault(); 496 497 gExtraDragTests++; 498 } 499 500 function doDragStartInput(event) 501 { 502 var dt = event.dataTransfer; 503 checkTypes(dt, ["text/plain"], 0, "initial input"); 504 505 is(SpecialPowers.wrap(dt).mozItemCount, 1, "initial input item count"); 506 // is(dt.getData("text/plain"), "Text", "input text/plain"); 507 508 // event.preventDefault(); 509 } 510 511 512 function doDragStartInShadowRoot(event) 513 { 514 is(event.type, "dragstart", "shadow root dragstart event type"); 515 is(event.target, $("shadow_host_containing_draggable"), "shadow root dragstart event target"); 516 is(event.bubbles, true, "shadow root dragstart event bubbles"); 517 is(event.cancelable, true, "shadow root dragstart event cancelable"); 518 519 event.preventDefault(); 520 521 gExtraDragTests++; 522 } 523 524 function doDragStartShadowRootImage(event) 525 { 526 var dt = event.dataTransfer; 527 528 checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list", 529 "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain", 530 "application/x-moz-nativeimage", "application/x-moz-file-promise", 531 "application/x-moz-file-promise-url", "application/x-moz-file-promise-dest-filename"], 532 0, "shadow root link with image"); 533 534 is(dt.getData("text/uri-list"), "http://example.org/", "shadow root link text/uri-list"); 535 is(dt.getData("text/plain"), "http://example.org/", "shadow root link text/plain"); 536 537 event.preventDefault(); 538 539 gExtraDragTests++; 540 } 541 542 function doDragStartSynthetic(event) 543 { 544 is(event.type, "dragstart", "synthetic dragstart event type"); 545 546 var dt = event.dataTransfer; 547 todo(dt instanceof DataTransfer, "synthetic dragstart dataTransfer is DataTransfer"); 548 // Uncomment next line once the todo instanceof above is fixed. 549 // checkTypes(dt, [], 0, "synthetic dragstart"); 550 551 is(event.detail, 1, "synthetic dragstart detail"); 552 is(event.screenX, 40, "synthetic dragstart screenX"); 553 is(event.screenY, 35, "synthetic dragstart screenY"); 554 is(event.clientX, 20, "synthetic dragstart clientX"); 555 is(event.clientY, 15, "synthetic dragstart clientY"); 556 is(event.ctrlKey, false, "synthetic dragstart ctrlKey"); 557 is(event.altKey, true, "synthetic dragstart altKey"); 558 is(event.shiftKey, false, "synthetic dragstart shiftKey"); 559 is(event.metaKey, false, "synthetic dragstart metaKey"); 560 is(event.button, 0, "synthetic dragstart button "); 561 is(event.relatedTarget, null, "synthetic dragstart relatedTarget"); 562 563 // Uncomment next two lines once the todo instanceof above is fixed. 564 // dt.setData("text/plain", "Text"); 565 // is(dt.getData("text/plain"), "Text", "synthetic dragstart data is set after adding"); 566 } 567 568 function doDragOverSynthetic(event) 569 { 570 is(event.type, "dragover", "synthetic dragover event type"); 571 572 var dt = event.dataTransfer; 573 todo(dt instanceof DataTransfer, "synthetic dragover dataTransfer is DataTransfer"); 574 // Uncomment next line once the todo instanceof above is fixed. 575 // checkTypes(dt, [], 0, "synthetic dragover"); 576 577 is(event.detail, 0, "synthetic dragover detail"); 578 is(event.screenX, 40, "synthetic dragover screenX"); 579 is(event.screenY, 35, "synthetic dragover screenY"); 580 is(event.clientX, 20, "synthetic dragover clientX"); 581 is(event.clientY, 15, "synthetic dragover clientY"); 582 is(event.ctrlKey, true, "synthetic dragover ctrlKey"); 583 is(event.altKey, false, "synthetic dragover altKey"); 584 is(event.shiftKey, true, "synthetic dragover shiftKey"); 585 is(event.metaKey, true, "synthetic dragover metaKey"); 586 is(event.button, 2, "synthetic dragover button"); 587 is(event.relatedTarget, document.documentElement, "synthetic dragover relatedTarget"); 588 589 // Uncomment next two lines once the todo instanceof above is fixed. 590 // dt.setData("text/plain", "Text"); 591 // is(dt.getData("text/plain"), "Text", "synthetic dragover data is set after adding"); 592 } 593 594 function onDragStartDraggable(event) 595 { 596 var dt = event.dataTransfer; 597 ok(SpecialPowers.wrap(dt).mozItemCount == 0 && !dt.types.length && event.originalTarget == gDragInfo.target, gDragInfo.testid); 598 599 event.preventDefault(); 600 gExtraDragTests++; 601 } 602 603 // Expects dt wrapped in SpecialPowers 604 function checkOneDataItem(dt, expectedtypes, expecteddata, index, testid) 605 { 606 checkTypes(dt, expectedtypes, index, testid); 607 for (var f = 0; f < expectedtypes.length; f++) { 608 if (index == 0) 609 is(dt.getData(expectedtypes[f]), expecteddata[f], testid + " getData " + expectedtypes[f]); 610 is(dt.mozGetDataAt(expectedtypes[f], index), expecteddata[f] ? expecteddata[f] : null, 611 testid + " getDataAt " + expectedtypes[f]); 612 } 613 } 614 615 function checkTypes(dt, expectedtypes, index, testid) 616 { 617 if (index == 0) { 618 var types = dt.types; 619 is(types.length, expectedtypes.length, testid + " types length"); 620 for (var f = 0; f < expectedtypes.length; f++) { 621 is(types[f], expectedtypes[f], testid + " " + types[f] + " check"); 622 } 623 } 624 625 types = SpecialPowers.wrap(dt).mozTypesAt(index); 626 if (gIsMac && expectedtypes.find((t) => t === "application/x-moz-nativeimage")) { 627 expectedtypes.push("text/x-moz-requestmime"); 628 } 629 is(types.length, expectedtypes.length, testid + " typesAt length"); 630 for (var f = 0; f < expectedtypes.length; f++) { 631 is(types[f], expectedtypes[f], testid + " " + types[f] + " at " + index + " check"); 632 } 633 } 634 635 // Expects dt wrapped in SpecialPowers 636 function checkURL(dt, url, fullurllist, index, testid) 637 { 638 is(dt.getData("text/uri-list"), fullurllist, testid + " text/uri-list"); 639 is(dt.getData("URL"), url, testid + " URL"); 640 is(dt.mozGetDataAt("text/uri-list", 0), fullurllist, testid + " text/uri-list"); 641 is(dt.mozGetDataAt("URL", 0), fullurllist, testid + " URL"); 642 } 643 644 function onDragOverDraggableFalse(event) { 645 ok(false, "Triggered dragstart on draggable=false node " + event.target.id); 646 } 647 648 function onDragStartUnlinkable(event) { 649 ok(false, "Triggered dragstart on undraggable node " + event.target.id); 650 } 651 652 function expectError(fn, eid, testid) 653 { 654 var error = ""; 655 try { 656 fn(); 657 } catch (ex) { 658 error = ex.name; 659 } 660 is(error, eid, testid + " causes exception " + eid); 661 } 662 663 </script> 664 665 </head> 666 667 <body style="height: 300px; overflow: auto;" onload="setTimeout(runTests, 0)"> 668 669 <div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div> 670 671 <fieldset> 672 <a id="link" href="http://www.mozilla.org/" ondragstart="doDragStartLink(event)">mozilla.org</a> 673 </fieldset> 674 675 <label> 676 <img id="image" src="data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%18%00%00%00%18%02%03%00%00%00%9D%19%D5k%00%00%00%04gAMA%00%00%B1%8F%0B%FCa%05%00%00%00%0CPLTE%FF%FF%FF%FF%FF%FF%F7%DC%13%00%00%00%03%80%01X%00%00%00%01tRNS%08N%3DPT%00%00%00%01bKGD%00%88%05%1DH%00%00%00%09pHYs%00%00%0B%11%00%00%0B%11%01%7Fd_%91%00%00%00%07tIME%07%D2%05%0C%14%0C%0D%D8%3F%1FQ%00%00%00%5CIDATx%9C%7D%8E%CB%09%C0%20%10D%07r%B7%20%2F%E9wV0%15h%EA%D9%12D4%BB%C1x%CC%5C%1E%0C%CC%07%C0%9C0%9Dd7()%C0A%D3%8D%E0%B8%10%1DiCHM%D0%AC%D2d%C3M%F1%B4%E7%FF%10%0BY%AC%25%93%CD%CBF%B5%B2%C0%3Alh%CD%AE%13%DF%A5%F7%E0%03byW%09A%B4%F3%E2%00%00%00%00IEND%AEB%60%82" 677 ondragstart="doDragStartImage(event)"> 678 </label> 679 680 <input id="input" value="Text in a box" ondragstart="doDragStartInput(event)"> 681 682 <div ondragstart="onDragStartDraggable(event)"> 683 <div id="dragtrue" draggable="true"> 684 This is a <span id="spantrue">draggable</span> area. 685 </div> 686 <div id="dragfalse" draggable="false"> 687 This is a <span id="spanfalse">non-draggable</span> area. 688 </div> 689 </div> 690 691 <!--iframe src="http://www.mozilla.org" width="400" height="400"></iframe--> 692 693 <div id="synthetic" ondragstart="doDragStartSynthetic(event)">Synthetic Event Dispatch</div> 694 <div id="synthetic2" ondragover="doDragOverSynthetic(event)">Synthetic Event Dispatch</div> 695 696 <div draggable="true" id="shadow_host_containing_draggable"></div> 697 698 <script> 699 shadow_host_containing_draggable.attachShadow({ mode: 'open' }).innerHTML = 700 `<span>Inside shadow root</span>`; 701 shadow_host_containing_draggable.addEventListener("dragstart", doDragStartInShadowRoot); 702 </script> 703 704 <a href="http://example.org" ondragstart="doDragStartShadowRootImage(event)"> 705 <div id="shadow_host_containing_image"></div> 706 </a> 707 708 <script> 709 shadow_host_containing_image.attachShadow({ mode: 'open' }).innerHTML = 710 `<img src="${$("image").src}" alt="Alt Text"></img>`; 711 </script> 712 713 <a href="http://example.org" id="link_user_select_none_child" draggable="false" ondragstart="onDragOverDraggableFalse(event)"> 714 <span id="userselectnone" style="user-select: none"> 715 This is an unselectable, undraggable area. 716 </span> 717 </a> 718 719 <div id="draggable_with_undraggable_descendant" draggable="true" ondragstart="onDragStartDraggable(event)"> 720 <a id="undraggable_inside_draggable" href="http://example.org" draggable="false" ondragstart="onDragOverDraggableFalse(event)"> 721 This is an undraggable link inside a draggable ancestor. 722 </a> 723 </div> 724 725 <a id="link_to_file" href="file:///" ondragstart="onDragStartUnlinkable(event)">This is an undraggable 'file' link</a> 726 <a id="link_to_windows_file" href="c:/Users/" ondragstart="onDragStartUnlinkable(event)">This is an undraggable 'file' link</a> 727 <a id="link_to_backslash_windows_file" href="c:\\Users\\" ondragstart="onDragStartUnlinkable(event)">This is an undraggable 'file' link</a> 728 <img id="broken_file_image" src="file:///" ondragstart="onDragStartUnlinkable(event)"> 729 <img id="broken_windows_file_image" src="c:/Users/" ondragstart="onDragStartUnlinkable(event)"> 730 <img id="broken_backslash_windows_file_image" src="c:\\Users\\" ondragstart="onDragStartUnlinkable(event)"> 731 </body> 732 </html>