DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (1aeaa33a64f9)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
<html>
<head>
  <title>Tests for the dragstart event</title>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>      
  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>      

<!--
 This test checks the dragstart event and the DataTransfer object
  -->
 
<script>

SimpleTest.waitForExplicitFinish();

var gDragInfo;
var gDataTransfer = null;
var gExtraDragTests = 0;

function runTests()
{
  // first, create a selection and try dragging it
  var draggable = $("draggable");
  window.getSelection().selectAllChildren(draggable);
  synthesizeMouse(draggable, 6, 6, { type: "mousedown" });
  synthesizeMouse(draggable, 14, 14, { type: "mousemove" });
  // drags are asynchronous on Linux, so this extra event is needed to make
  // sure the drag gets processed
  synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
}

function afterDragTests()
{
  // the dragstart should have occurred due to moving the mouse. gDataTransfer
  // caches the dataTransfer that was used, however it should now be empty and
  // be read only.
  ok(gDataTransfer instanceof DataTransfer, "DataTransfer after dragstart event");
  checkTypes(gDataTransfer, [], 0, "after dragstart event");

  expectError(() => gDataTransfer.setData("text/plain", "Some Text"),
              "NoModificationAllowedError", "setData when read only");
  expectError(() => gDataTransfer.clearData("text/plain"),
              "NoModificationAllowedError", "clearData when read only");
  expectError(() => gDataTransfer.mozSetDataAt("text/plain", "Some Text", 0),
              "NoModificationAllowedError", "setDataAt when read only");
  expectError(() => gDataTransfer.mozClearDataAt("text/plain", 0),
              "NoModificationAllowedError", "clearDataAt when read only");
  expectError(() => gDataTransfer.addElement(draggable),
              "NoModificationAllowedError", "addElement when read only");

  var evt = document.createEvent("dragevent");
  ok(evt instanceof DragEvent, "synthetic dragevent class")
  ok(evt instanceof MouseEvent, "synthetic event inherits from MouseEvent")
  evt.initDragEvent("dragstart", true, true, window, 1, 40, 35, 20, 15,
                    false, true, false, false, 0, null, null);
  $("synthetic").dispatchEvent(evt);

  var evt = document.createEvent("dragevent");
  ok(evt instanceof DragEvent, "synthetic dragevent class")
  evt.initDragEvent("dragover", true, true, window, 0, 40, 35, 20, 15,
                    true, false, true, true, 2, document.documentElement, null);
  $("synthetic2").dispatchEvent(evt);

  // next, dragging links and images
  sendMouseEventsForDrag("link");
  sendMouseEventsForDrag("image");

//  disable testing input dragging for now, as it doesn't seem to be testable 
//  draggable = $("input");
//  draggable.setSelectionRange(0, 4);
//  synthesizeMouse(draggable, 8, 8, { type: "mousedown" });
//  synthesizeMouse(draggable, 15, 15, { type: "mousemove" });
//  sendMouseEventsForDrag("input");

  // next, check if the draggable attribute can be used to adjust the drag target
  gDragInfo = { target: $("dragtrue"), testid: "draggable true node" };
  sendMouseEventsForDrag("dragtrue");
  gDragInfo = { target: $("dragtrue"), testid: "draggable true child" };
  sendMouseEventsForDrag("spantrue");
  gDragInfo = { target: $("dragfalse").firstChild, testid: "draggable false node" };
  sendMouseEventsForDrag("dragfalse");
  gDragInfo = { target: $("spanfalse").firstChild, testid: "draggable false child" };
  sendMouseEventsForDrag("spanfalse");

  synthesizeMouse(draggable, 12, 12, { type: "mouseup" });
  if (gExtraDragTests == 4)
    SimpleTest.finish();
}

function sendMouseEventsForDrag(nodeid)
{
  var draggable = $(nodeid);
  synthesizeMouse(draggable, 3, 3, { type: "mousedown" });
  synthesizeMouse(draggable, 10, 10, { type: "mousemove" });
  synthesizeMouse(draggable, 12, 12, { type: "mousemove" });
}

function doDragStartSelection(event)
{
  is(event.type, "dragstart", "dragstart event type");
  is(event.target, $("draggable").firstChild, "dragstart event target");
  is(event.bubbles, true, "dragstart event bubbles");
  is(event.cancelable, true, "dragstart event cancelable");

  is(event.clientX, 14, "dragstart clientX");
  is(event.clientY, 14, "dragstart clientY");
  ok(event.screenX > 0, "dragstart screenX");
  ok(event.screenY > 0, "dragstart screenY");
  is(event.layerX, 14, "dragstart layerX");
  is(event.layerY, 14, "dragstart layerY");
  is(event.pageX, 14, "dragstart pageX");
  is(event.pageY, 14, "dragstart pageY");

  var dt = event.dataTransfer;
  ok(dt instanceof DataTransfer, "dataTransfer is DataTransfer");
  gDataTransfer = dt;

  var types = dt.types;
  ok(Array.isArray(types), "initial types is an Array");
  checkTypes(dt, ["text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial selection");

  is(dt.getData("text/plain"), "This is a draggable bit of text.", "initial selection text/plain");
  is(dt.getData("text/html"), "<div id=\"draggable\" ondragstart=\"doDragStartSelection(event)\">This is a <em>draggable</em> bit of text.</div>",
     "initial selection text/html");

  // text/unicode and Text are available for compatibility. They retrieve the
  // text/plain data
  is(dt.getData("text/unicode"), "This is a draggable bit of text.", "initial selection text/unicode");
  is(dt.getData("Text"), "This is a draggable bit of text.", "initial selection Text");
  is(dt.getData("TEXT"), "This is a draggable bit of text.", "initial selection TEXT");
  is(dt.getData("text/UNICODE"), "This is a draggable bit of text.", "initial selection text/UNICODE"); 

  is(dt.mozItemCount, 1, "initial selection item count");

  dt.clearData("text/plain");
  dt.clearData("text/html");
  dt.clearData("text/_moz_htmlinfo");
  dt.clearData("text/_moz_htmlcontext");

  test_DataTransfer(dt);
  setTimeout(afterDragTests, 0);
}

function test_DataTransfer(dt)
{
  is(dt.mozItemCount, 0, "empty itemCount");

  var types = dt.types;
  ok(Array.isArray(types), "empty types is an Array");
  checkTypes(dt, [], 0, "empty");
  is(dt.getData("text/plain"), "", "empty data is empty");

  // calling setDataAt requires an index that is 0 <= index <= dt.itemCount
  expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 1),
              "IndexSizeError", "setDataAt index too high");

  is(dt.mozUserCancelled, false, "userCancelled");

  // because an exception occurred, the data should not have been added
  is(dt.mozItemCount, 0, "empty setDataAt index too high itemCount");
  dt.getData("text/plain", "", "empty setDataAt index too high getData");

  // if the type is '', do nothing, or return ''
  dt.setData("", "Invalid Type");
  is(dt.types.length, 0, "invalid type setData");
  is(dt.getData(""), "", "invalid type getData"),
  dt.mozSetDataAt("", "Invalid Type", 0);
  is(dt.types.length, 0, "invalid type setDataAt");
  is(dt.mozGetDataAt("", 0), null, "invalid type getDataAt"),

  // similar with clearDataAt and getDataAt
  expectError(() => dt.mozGetDataAt("text/plain", 1),
              "IndexSizeError", "getDataAt index too high");
  expectError(() => dt.mozClearDataAt("text/plain", 1),
              "IndexSizeError", "clearDataAt index too high");

  dt.setData("text/plain", "Sample Text");
  is(dt.mozItemCount, 1, "added plaintext itemCount");
  checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext");

   // after all those exceptions, the data should still be the same
  checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "added plaintext after exception");

  // modifying the data associated with the format should give it the new value
  dt.setData("text/plain", "Modified Text");
  is(dt.mozItemCount, 1, "modified plaintext itemCount");
  checkOneDataItem(dt, ["text/plain"], ["Modified Text"], 0, "modified plaintext");

  dt.setData("text/html", "<strong>Modified Text</strong>");
  is(dt.mozItemCount, 1, "modified html itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                       ["Modified Text", "<strong>Modified Text</strong>"],
                       0, "modified html");

  // modifying data for a type that already exists should adjust it in place,
  // not reinsert it at the beginning
  dt.setData("text/plain", "New Text");
  is(dt.mozItemCount, 1, "modified text again itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                       ["New Text", "<strong>Modified Text</strong>"],
                       0, "modified text again");

  var draggable = $("draggable");
  dt.setData("application/-moz-node", draggable);
  checkOneDataItem(dt, ["text/plain", "text/html", "application/-moz-node"],
                       ["New Text", "<strong>Modified Text</strong>", draggable.toString()],
                       0, "added node");

  dt.clearData(""); // null means clear all
  is(dt.mozItemCount, 0, "itemCount after clearData empty string");
  checkTypes(dt, [], 0, "empty after clearData empty string");
  
  dt.setData("text/plain", 22);
  dt.setData("text/html", 5.6);
  dt.setData("text/xml", 5.6);
  checkTypes(dt, ["text/plain", "text/html", "text/xml"], ["22", "5.6", ""], 0, "add numeric and empty data");

  dt.clearData(); // no argument means clear all
  is(dt.mozItemCount, 0, "itemCount after clearData no argument");
  checkTypes(dt, [], 0, "empty after clearData no argument");

  // check 'Text' type which should convert into text/plain
  dt.setData("Text", "Sample Text");
  checkOneDataItem(dt, ["text/plain"], ["Sample Text"], 0, "set Text");
  is(dt.getData("Text"), "Sample Text", "getData Text");
  is(dt.mozGetDataAt("Text", 0), "Sample Text", "getDataAt Text");
  dt.setData("text/plain", "More Text");
  checkOneDataItem(dt, ["text/plain"], ["More Text"], 0, "set text/plain after set Text");

  dt.mozClearDataAt("", 0); // null means clear all
  is(dt.mozItemCount, 0, "itemCount after clearDataAt empty string");
  checkTypes(dt, [], 0, "empty after clearDataAt empty string");

  // check text/uri-list type
  dt.setData("text/uri-list", "http://www.mozilla.org");
  checkURL(dt, "http://www.mozilla.org", "http://www.mozilla.org", 0, "set text/uri-list");

  // check URL type which should add text/uri-list data
  dt.setData("URL", "ftp://ftp.example.com");
  checkURL(dt, "ftp://ftp.example.com", "ftp://ftp.example.com", 0, "set URL");
  checkTypes(dt, ["text/uri-list"], ["ftp://ftp.example.com"], "url types");

  // clearing text/uri-list data
  dt.clearData("text/uri-list");
  is(dt.mozItemCount, 0, "itemCount after clear url-list");
  is(dt.getData("text/uri-list"), "", "text/uri-list after clear url-list");
  is(dt.getData("URL"), "", "URL after clear url-list");

  // check text/uri-list parsing
  dt.setData("text/uri-list", "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com");
  checkURL(dt, "http://www.xulplanet.com",
           "#http://www.mozilla.org\nhttp://www.xulplanet.com\nhttp://www.example.com",
           0, "uri-list 3 lines");

  dt.setData("text/uri-list", "#http://www.mozilla.org");
  is(dt.getData("URL"), "", "uri-list commented");
  dt.setData("text/uri-list", "#http://www.mozilla.org\n");
  is(dt.getData("URL"), "", "uri-list commented with newline");

  // check that clearing the URL type also clears the text/uri-list type
  dt.clearData("URL");
  is(dt.getData("text/uri-list"), "", "clear URL");

  dt.setData("text/uri-list", "#http://www.mozilla.org\n\n\n\n\n");
  is(dt.getData("URL"), "", "uri-list with blank lines");
  dt.setData("text/uri-list", "");
  is(dt.getData("URL"), "", "empty uri-list");
  dt.setData("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com  \r\n");
  is(dt.getData("URL"), "http://www.xulplanet.com", "uri-list mix");
  dt.setData("text/uri-list", "\nhttp://www.mozilla.org");
  is(dt.getData("URL"), "", "empty line to start uri-list");
  dt.setData("text/uri-list", "  http://www.mozilla.org#anchor  ");
  is(dt.getData("URL"), "http://www.mozilla.org#anchor", "uri-list with spaces and hash");

  // ensure that setDataAt works the same way
  dt.mozSetDataAt("text/uri-list", "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com  \r\n", 0);
  checkURL(dt, "http://www.xulplanet.com",
           "#http://www.mozilla.org\n#Sample\nhttp://www.xulplanet.com  \r\n",
           0, "uri-list mix setDataAt");

  // now test adding multiple items to be dragged using the setDataAt method
  dt.clearData();
  dt.mozSetDataAt("text/plain", "First Item", 0);
  dt.mozSetDataAt("text/plain", "Second Item", 1);
  expectError(() => dt.mozSetDataAt("text/plain", "Some Text", 3),
              "IndexSizeError", "setDataAt index too high with two items");
  is(dt.mozItemCount, 2, "setDataAt item itemCount");
  checkOneDataItem(dt, ["text/plain"], ["First Item"], 0, "setDataAt item at index 0");
  checkOneDataItem(dt, ["text/plain"], ["Second Item"], 1, "setDataAt item at index 1");

  dt.mozSetDataAt("text/html", "<em>First Item</em>", 0);
  dt.mozSetDataAt("text/html", "<em>Second Item</em>", 1);
  is(dt.mozItemCount, 2, "setDataAt two types item itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "<em>First Item</em>"], 0, "setDataAt two types item at index 0");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["Second Item", "<em>Second Item</em>"], 1, "setDataAt two types item at index 1");

  dt.mozSetDataAt("text/html", "<em>Changed First Item</em>", 0);
  dt.mozSetDataAt("text/plain", "Changed Second Item", 1);
  is(dt.mozItemCount, 2, "changed with setDataAt item itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "<em>Changed First Item</em>"], 0, "changed with setDataAt item at index 0");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setDataAt item at index 1");

  dt.setData("text/html", "Changed with setData");
  is(dt.mozItemCount, 2, "changed with setData");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "Changed with setData"], 0, "changed with setData item at index 0");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setData item at index 1");

  dt.mozSetDataAt("application/-moz-node", "draggable", 2);
  is(dt.mozItemCount, 3, "setDataAt node itemCount");
  checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2");

  // Try to add and then remove a non-string type to the DataTransfer and ensure
  // that the type appears in DataTransfer.types. These calls need to be called
  // with SpecialPowers.wrap(), as adding and removing non-string/file types to
  // DataTransfer is chrome-only.
  {
    SpecialPowers.wrap(dt).mozSetDataAt("application/-x-body", document.body, 0);
    let found = false;
    for (let i = 0; i < dt.types.length; ++i) {
      if (dt.types[i] == "application/-x-body") {
        found = true;
        break;
      }
    }
    ok(found, "Data should appear in datatransfer.types despite having a non-string type");
    SpecialPowers.wrap(dt).mozClearDataAt("application/-x-body", 0);
  }

  dt.mozClearDataAt("text/html", 1);
  is(dt.mozItemCount, 3, "clearDataAt itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "Changed with setData"], 0, "clearDataAt item at index 0");
  checkOneDataItem(dt, ["text/plain"], ["Changed Second Item"], 1, "clearDataAt item at index 1");

  dt.mozClearDataAt("text/plain", 1);
  is(dt.mozItemCount, 2, "clearDataAt last type itemCount");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "Changed with setData"], 0, "clearDataAt last type at index 0");
  checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 1, "clearDataAt last type item at index 2");
  expectError(() => dt.mozGetDataAt("text/plain", 2),
              "IndexSizeError", "getDataAt after item removed index too high");

  dt.mozSetDataAt("text/unknown", "Unknown type", 2);
  dt.mozSetDataAt("text/unknown", "Unknown type", 1);
  is(dt.mozItemCount, 3, "add unknown type");
  checkOneDataItem(dt, ["application/-moz-node", "text/unknown"],
                   ["draggable", "Unknown type"], 1, "add unknown type item at index 1");
  checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 2, "add unknown type item at index 2");

  dt.mozClearDataAt("", 1);
  is(dt.mozItemCount, 2, "clearDataAt empty string");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "Changed with setData"], 0, "clearDataAt empty string item at index 0");
  checkOneDataItem(dt, ["text/unknown"],
                   ["Unknown type"], 1, "clearDataAt empty string item at index 1");

  // passing a format that doesn't exist to clearData or clearDataAt should just
  // do nothing
  dt.clearData("text/something");
  dt.mozClearDataAt("text/something", 1);
  is(dt.mozItemCount, 2, "clearData type that does not exist");
  checkOneDataItem(dt, ["text/plain", "text/html"],
                   ["First Item", "Changed with setData"], 0, "clearData type that does not exist item at index 0");
  checkOneDataItem(dt, ["text/unknown"],
                   ["Unknown type"], 1, "clearData type that does not exist item at index 1");

  expectError(() => dt.mozClearDataAt("text/plain", 3),
              "IndexSizeError", "clearData index too high with two items");

  // ensure that clearData() removes all data associated with the first item, but doesn't
  // shift the second item down into the first item's slot.
  dt.clearData();
  is(dt.mozItemCount, 2, "clearData no argument with multiple items itemCount");
  checkOneDataItem(dt, [], [], 0,
                   "clearData no argument with multiple items item at index 0");
  checkOneDataItem(dt, ["text/unknown"],
                   ["Unknown type"], 1, "clearData no argument with multiple items item at index 1");

  // remove tha remaining data in index 1. As index 0 is empty at this point, this will actually
  // drop mozItemCount to 0. (XXX: This is because of spec-compliance reasons related
  // to the more-recent dt.item API. It's an unfortunate, but hopefully rare edge case)
  dt.mozClearDataAt("", 1);
  is(dt.mozItemCount, 0, "all data cleared");

  // now check the effectAllowed and dropEffect properties
  is(dt.dropEffect, "none", "initial dropEffect");
  is(dt.effectAllowed, "uninitialized", "initial effectAllowed");

  ["copy", "none", "link", "", "other", "copyMove", "all", "uninitialized", "move"].forEach(
    function (i) {
      dt.dropEffect = i;
      is(dt.dropEffect, i == "" || i == "other" || i == "copyMove" ||
                        i == "all" || i == "uninitialized" ? "link" : i,
         "dropEffect set to " + i);
      is(dt.effectAllowed, "uninitialized", "effectAllowed not modified by dropEffect set to " + i);
    }
  );

  ["move", "copy", "link", "", "other", "moveCopy", "copyMove",
   "linkMove", "copyLink", "all", "uninitialized", "none"].forEach(
    function (i) {
      dt.effectAllowed = i;
      is(dt.dropEffect, "move", "dropEffect not modified by effectAllowed set to " + i);
      is(dt.effectAllowed, i == "" || i == "other" || i == "moveCopy" ? "link" : i,
         "effectAllowed set to " + i);
    }
  );
}

function doDragStartLink(event)
{
  var dt = event.dataTransfer;
  checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
                  "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial link");

  is(dt.mozItemCount, 1, "initial link item count");
  is(dt.getData("text/uri-list"), "http://www.mozilla.org/", "link text/uri-list");
  is(dt.getData("text/plain"), "http://www.mozilla.org/", "link text/plain");

  event.preventDefault();

  gExtraDragTests++;
}

function doDragStartImage(event)
{
  var dataurl = $("image").src;

  var dt = event.dataTransfer;
  checkTypes(dt, ["text/x-moz-url", "text/x-moz-url-data", "text/x-moz-url-desc", "text/uri-list",
                  "text/_moz_htmlcontext", "text/_moz_htmlinfo", "text/html", "text/plain"], 0, "initial image");

  is(dt.mozItemCount, 1, "initial image item count");
  is(dt.getData("text/uri-list"), dataurl, "image text/uri-list");
  is(dt.getData("text/plain"), dataurl, "image text/plain");

  event.preventDefault();

  gExtraDragTests++;
}

function doDragStartInput(event)
{
  var dt = event.dataTransfer;
  checkTypes(dt, ["text/plain"], 0, "initial input");

  is(dt.mozItemCount, 1, "initial input item count");
//  is(dt.getData("text/plain"), "Text", "input text/plain");

//  event.preventDefault();
}

function doDragStartSynthetic(event)
{
  is(event.type, "dragstart", "synthetic dragstart event type");

  var dt = event.dataTransfer;
  todo(dt instanceof DataTransfer, "synthetic dragstart dataTransfer is DataTransfer");
//  Uncomment next line once the todo instanceof above is fixed.
//  checkTypes(dt, [], 0, "synthetic dragstart");

  is(event.detail, 1, "synthetic dragstart detail");
  is(event.screenX, 40, "synthetic dragstart screenX");
  is(event.screenY, 35, "synthetic dragstart screenY");
  is(event.clientX, 20, "synthetic dragstart clientX");
  is(event.clientY, 15, "synthetic dragstart clientY");
  is(event.ctrlKey, false, "synthetic dragstart ctrlKey");
  is(event.altKey, true, "synthetic dragstart altKey");
  is(event.shiftKey, false, "synthetic dragstart shiftKey");
  is(event.metaKey, false, "synthetic dragstart metaKey");
  is(event.button, 0, "synthetic dragstart button ");
  is(event.relatedTarget, null, "synthetic dragstart relatedTarget");

//  Uncomment next two lines once the todo instanceof above is fixed.
//  dt.setData("text/plain", "Text");
//  is(dt.getData("text/plain"), "Text", "synthetic dragstart data is set after adding");
}

function doDragOverSynthetic(event)
{
  is(event.type, "dragover", "synthetic dragover event type");

  var dt = event.dataTransfer;
  todo(dt instanceof DataTransfer, "synthetic dragover dataTransfer is DataTransfer");
//  Uncomment next line once the todo instanceof above is fixed.
// checkTypes(dt, [], 0, "synthetic dragover");

  is(event.detail, 0, "synthetic dragover detail");
  is(event.screenX, 40, "synthetic dragover screenX");
  is(event.screenY, 35, "synthetic dragover screenY");
  is(event.clientX, 20, "synthetic dragover clientX");
  is(event.clientY, 15, "synthetic dragover clientY");
  is(event.ctrlKey, true, "synthetic dragover ctrlKey");
  is(event.altKey, false, "synthetic dragover altKey");
  is(event.shiftKey, true, "synthetic dragover shiftKey");
  is(event.metaKey, true, "synthetic dragover metaKey");
  is(event.button, 2, "synthetic dragover button");
  is(event.relatedTarget, document.documentElement, "synthetic dragover relatedTarget");

//  Uncomment next two lines once the todo instanceof above is fixed.
//  dt.setData("text/plain", "Text");
//  is(dt.getData("text/plain"), "Text", "synthetic dragover data is set after adding");
}

function onDragStartDraggable(event)
{
  var dt = event.dataTransfer;
  ok(dt.mozItemCount == 0 && dt.types.length == 0 && event.originalTarget == gDragInfo.target, gDragInfo.testid);

  gExtraDragTests++;
}

function checkOneDataItem(dt, expectedtypes, expecteddata, index, testid)
{
  checkTypes(dt, expectedtypes, index, testid);
  for (var f = 0; f < expectedtypes.length; f++) {
    if (index == 0)
      is(dt.getData(expectedtypes[f]), expecteddata[f], testid + " getData " + expectedtypes[f]);
    is(dt.mozGetDataAt(expectedtypes[f], index), expecteddata[f] ? expecteddata[f] : null,
       testid + " getDataAt " + expectedtypes[f]);
  }
}

function checkTypes(dt, expectedtypes, index, testid)
{
  if (index == 0) {
    var types = dt.types;
    is(types.length, expectedtypes.length, testid + " types length");
    for (var f = 0; f < expectedtypes.length; f++) {
      is(types[f], expectedtypes[f], testid + " " + types[f] + " check");
    }
  }

  types = dt.mozTypesAt(index);
  is(types.length, expectedtypes.length, testid + " typesAt length");
  for (var f = 0; f < expectedtypes.length; f++) {
    is(types[f], expectedtypes[f], testid + " " + types[f] + " at " + index + " check");
  }
}

function checkURL(dt, url, fullurllist, index, testid)
{
  is(dt.getData("text/uri-list"), fullurllist, testid + " text/uri-list");
  is(dt.getData("URL"), url, testid + " URL");
  is(dt.mozGetDataAt("text/uri-list", 0), fullurllist, testid + " text/uri-list");
  is(dt.mozGetDataAt("URL", 0), fullurllist, testid + " URL");
}

function expectError(fn, eid, testid)
{
  var error = "";
  try {
    fn();
  } catch (ex) {
    error = ex.name;
  }
  is(error, eid, testid + " causes exception " + eid);
}

</script>

</head>

<body style="height: 300px; overflow: auto;" onload="setTimeout(runTests, 0)">

<div id="draggable" ondragstart="doDragStartSelection(event)">This is a <em>draggable</em> bit of text.</div>

<fieldset>
<a id="link" href="http://www.mozilla.org/" ondragstart="doDragStartLink(event)">mozilla.org</a>
</fieldset>

<label>
<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"
     ondragstart="doDragStartImage(event)">
</label>

<input id="input" value="Text in a box" ondragstart="doDragStartInput(event)">

<div ondragstart="onDragStartDraggable(event)">
  <div id="dragtrue" draggable="true">
    This is a <span id="spantrue">draggable</span> area.
  </div>
  <div id="dragfalse" draggable="false">
    This is a <span id="spanfalse">non-draggable</span> area.
  </div>
</div>

<!--iframe src="http://www.mozilla.org" width="400" height="400"></iframe-->

<div id="synthetic" ondragstart="doDragStartSynthetic(event)">Synthetic Event Dispatch</div>
<div id="synthetic2" ondragover="doDragOverSynthetic(event)">Synthetic Event Dispatch</div>

</body>
</html>