summaryrefslogtreecommitdiffstats
path: root/dom/events/test/test_DataTransferItemList.html
blob: 1d093c8cf756144d0c503052108c5a9fe6698371 (plain)
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
<html>
<head>
  <title>Tests for the DataTransferItemList object</title>
  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body style="height: 300px; overflow: auto;">
<p id="display"> </p>
<img id="image" draggable="true" 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">
<div id="over" style="width: 100px; height: 100px; border: 2px black dashed;">
  drag over here
</div>

<script>
  function spin() {
    // Defer to the event loop twice to wait for any events to be flushed out.
    return new Promise(function(a) {
      SimpleTest.executeSoon(function() {
        SimpleTest.executeSoon(a)
      });
    });
  }

  add_task(async function() {
    await spin();
    var draggable = document.getElementById('image');
    var over = document.getElementById('over');

    var dragstartFired = 0;
    draggable.addEventListener('dragstart', onDragStart);
    function onDragStart(e) {
      draggable.removeEventListener('dragstart', onDragStart);

      var dt = e.dataTransfer;
      dragstartFired++;

      ok(true, "dragStart event fired");
      var dtList = e.dataTransfer.items;
      ok(dtList instanceof DataTransferItemList,
         "DataTransfer.items returns a DataTransferItemList");

      for (var i = 0; i < dtList.length; i++) {
        var item = dtList[i];
        ok(item instanceof DataTransferItem,
           "operator[] returns DataTransferItem objects");
        if (item.kind == "file") {
          var file = item.getAsFile();
          ok(file instanceof File, "getAsFile() returns File objects");
        }
      }

      dtList.clear();
      is(dtList.length, 0, "after .clear() DataTransferItemList should be empty");

      dtList.add("this is some text", "text/plain");
      dtList.add("<a href='www.mozilla.org'>this is a link</a>", "text/html");
      dtList.add("http://www.mozilla.org", "text/uri-list");
      dtList.add("this is custom-data", "custom-data");


      var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html",
                          {type: "text/html"});

      dtList.add(file);

      checkTypes(["text/plain", "text/html", "text/uri-list", "custom-data", "text/html"],
                 dtList, "DataTransferItemList.add test");

      var files = e.dataTransfer.files;
      is(files.length, 1, "DataTransfer.files should contain the one file we added earlier");
      is(files[0], file, "It should be the same file as the file we originally created");
      is(file, e.dataTransfer.mozGetDataAt("text/html", 1),
         "It should be stored in index 1 for mozGetDataAt");

      var file2 = new File(['<a id="c"><b id="d">yo!</b></a>'], "myotherfile.html",
                           {type: "text/html"});
      dtList.add(file2);

      todo(files.length == 2, "This test has chrome privileges, so the FileList objects aren't updated live");
      files = e.dataTransfer.files;
      is(files.length, 2, "The files property should have been updated in place");
      is(files[1], file2, "It should be the same file as the file we originally created");
      is(file2, e.dataTransfer.mozGetDataAt("text/html", 2),
         "It should be stored in index 2 for mozGetDataAt");

      var oldLength = dtList.length;
      var randomString = "foo!";
      e.dataTransfer.mozSetDataAt("random/string", randomString, 3);
      is(oldLength, dtList.length,
         "Adding a non-file entry to a non-zero index should not add an item to the items list");

      var file3 = new File(['<a id="e"><b id="f">heya!</b></a>'], "yetanotherfile.html",
                           {type: "text/html"});
      e.dataTransfer.mozSetDataAt("random/string", file3, 3);
      is(oldLength + 1, dtList.length,
         "Replacing the entry with a file should add it to the list!");
      is(dtList[oldLength].getAsFile(), file3, "It should be stored in the last index as a file");
      is(dtList[oldLength].type, "text/html", "It should have the correct type");
      is(dtList[oldLength].kind, "file", "It should have the correct kind");

      todo(files.length == 3, "This test has chrome privileges, so the FileList objects aren't updated live");
      files = e.dataTransfer.files;
      is(files[files.length - 1], file3, "It should also be in the files list");

      oldLength = dtList.length;
      var nonstring = {};
      e.dataTransfer.mozSetDataAt("jsobject", nonstring, 0);
      is(oldLength + 1, dtList.length,
         "Adding a non-string object using the mozAPIs to index 0 should add an item to the dataTransfer");
      is(dtList[oldLength].type, "jsobject", "It should have the correct type");
      is(dtList[oldLength].kind, "other", "It should have the correct kind");

      // Clear the event's data and get it set up so we can read it later!
      dtList.clear();

      dtList.add(file);
      dtList.add("this is some text", "text/plain");
      is(e.dataTransfer.mozGetDataAt("text/html", 1), file);
    }

    var getAsStringCalled = 0;
    var dragenterFired = 0;
    over.addEventListener('dragenter', onDragEnter);
    function onDragEnter(e) {
      over.removeEventListener('dragenter', onDragEnter);

      var dt = e.dataTransfer;
      dragenterFired++;

      // NOTE: This test is run with chrome privileges.
      // For back-compat reasons, protected mode acts like readonly mode for
      // chrome documents.
      readOnly(e);
    }

    var dropFired = 0;
    over.addEventListener('drop', onDrop);
    function onDrop(e) {
      over.removeEventListener('drop', onDrop);

      var dt = e.dataTransfer;
      dropFired++;
      e.preventDefault();

      readOnly(e);
    }


    function readOnly(e) {
      var dtList = e.dataTransfer.items;
      var num = dtList.length;

      // .clear() should have no effect
      dtList.clear();
      is(dtList.length, num,
         ".clear() should have no effect on the object during a readOnly event");

      // .remove(i) should throw InvalidStateError
      for (var i = 0; i < dtList.length; i++) {
        expectError(function() { dtList.remove(i); },
                    "InvalidStateError", ".remove(" + i + ") during a readOnly event");
      }

      // .add() should return null and have no effect
      var data = [["This is a plain string",  "text/plain"],
                  ["This is <em>HTML!</em>",  "text/html"],
                  ["http://www.mozilla.org/", "text/uri-list"],
                  ["this is some custom data", "custom-data"]];

      for (var i = 0; i < data.length; i++) {
        is(dtList.add(data[i][0], data[i][1]), null,
           ".add() should return null during a readOnly event");

        is(dtList.length, num, ".add() should have no effect during a readOnly event");
      }

      // .add() with a file should return null and have no effect
      var file = new File(['<a id="a"><b id="b">hey!</b></a>'], "myfile.html",
                          {type: "text/html"});
      is(dtList.add(file), null, ".add() with a file should return null during a readOnly event");
      is(dtList.length, num, ".add() should have no effect during a readOnly event");

      // We should be able to access the files
      is(e.dataTransfer.files.length, 1, "Should be able to access files");
      ok(e.dataTransfer.files[0], "File should be the same file!");
      is(e.dataTransfer.items.length, 2, "Should be able to see there are 2 items");

      is(e.dataTransfer.items[0].kind, "file", "First item should be a file");
      is(e.dataTransfer.items[1].kind, "string", "Second item should be a string");

      is(e.dataTransfer.items[0].type, "text/html", "first item should be text/html");
      is(e.dataTransfer.items[1].type, "text/plain", "second item should be text/plain");

      ok(e.dataTransfer.items[0].getAsFile(), "Should be able to get file");
      e.dataTransfer.items[1].getAsString(function(s) {
        getAsStringCalled++;
        is(s, "this is some text", "Should provide the correct string");
      });
    }

    synthesizeDrop(draggable, over, null, null);

    // Wait for the getAsString callbacks to complete
    await spin();
    is(getAsStringCalled, 2, "getAsString should be called twice");

    // Sanity-check to make sure that the events were actually run
    is(dragstartFired, 1, "dragstart fired");
    is(dragenterFired, 1, "dragenter fired");
    is(dropFired, 1, "drop fired");
  });

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

  function checkTypes(aExpectedList, aDtList, aTestid) {
    is(aDtList.length, aExpectedList.length, aTestid + " length test");
    for (var i = 0; i < aExpectedList.length; i++) {
      is(aDtList[i].type, aExpectedList[i], aTestid + " type " + i);
    }
  }
</script>

</body>
</html>