This repository has been archived by the owner on Nov 28, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
proposal.html
406 lines (357 loc) · 30.7 KB
/
proposal.html
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
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Directory Upload</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c-common" async class="remove"></script>
<script class="remove">
var respecConfig = {
shortName: "DirectoryUpload",
specStatus: "webspec",
editors: [{name: "Ali Alabbas", company: "Microsoft"},
{name: "Jonathan Watt", company: "Mozilla"},
{name: "Arun Ranganathan", company: "Mozilla"}],
processVersion: 2005,
wg: "Web Platform Incubator Community Group",
wgURI: "https://www.w3.org/community/wicg/",
wgPublicList: "public-wicg",
subjectPrefix: "[directory-upload]",
repository: "wicg/directory-upload",
};
</script>
</head>
<body>
<section id="abstract">
<p>
This spec enables directory uploading by allowing a developer to read directory contents (files and sub-directories) asynchronously and be able to identify the directory structure. This specification proposes changes to [[!HTML]] (in particular, additional API surface on <code>HTMLInputElement</code>, along with an additional atribute on the <code><input ...> </code>element) as well as a new specification called <em>Directory Upload</em> which brings directories to the web.
</p>
</section>
<section id="sotd">
<p>
This spec is currently being proposed within the WICG (Web Incubator Community Group) with the expectation that there may be changes, and that aspects of this proposal will eventually be part of the [[!HTML]] and [[!FileAPI]] standards.
</p>
</section>
<section class="informative">
<h2>Introduction</h2>
<section>
<h2>Background</h2>
<p>Websites are currently able to provide functionality for uploading files by using <code class="hightlight"><input type="file" multiple></code> and drag and drop. However, there currently is no standard solution to handle directories and cases that involve a mix of files and directories. This spec will provide the necessary mechanisms to enable directory uploading.</p>
</section>
<section>
<h2>Scenarios</h2>
<p>The following scenarios are in scope for this spec:</p>
<ol>
<li>Users are able to select one or more directories using a file dialog</li>
<li>Users are able to select a combination of directories and files using a file dialog</li>
<li>Users are able to select one or more directories via drag and drop</li>
<li>Users are able to select a combination of directories and files via drag and drop</li>
</ol>
<p>To address scenario 1 and 2, the HTML5 input tag needs a new attribute that can allow a user to select a directory as well as files. In addition, the <code>HTMLInputElement</code> requires a method for retrieving all the files and directories chosen so they can be traversed. For scenario 3 and 4, <code>DataTransfer</code> needs a method for retrieving all the files and directories dropped in so they can be traversed. To enable these scenarios, a <a>Directory</a> interface needs to be defined allowing the following: retrieving a list of its contents, reporting its relative path, and reporting its name.</p>
</section>
</section>
<section>
<h2>Model</h2>
<section>
<h3>Directory, File, Root, and Path</h3>
<p>In this specification, a <dfn id="directoryConcept">directory</dfn> is a logical organizing storage unit with a distinct <dfn>name</dfn> which contains <a href="#fileConcept">files</a> and/or one or more <dfn id="subdirectoryConcept">subdirectory</dfn> units (which are themselves <a href="#directoryConcept">directories</a>). A <a href="#directoryConcept">directory</a> corresponds to the same concept from the underlying OS filesystem, which is also called a <em>folder</em> on some underlying OS filesystems. A <dfn id="fileConcept">file</dfn> is <em>durable binary data</em> retrieved from the underlying OS filesystem, and can be programmatically manipulated by web applications as defined in the [[!FileAPI]]. In this specification, <a href="#fileConcept">files</a> and <a href="#directoryConcept">directories</a> which are selected by the user are represented by a <a>temporary directory tree</a>. <a href="fileConcept">Files</a> and <a href="#directoryConcept">directories</a> selected by the user have a position on the <a>temporary directory tree</a> that can be represented by a string, called a <dfn>path</dfn>. The <a>path</a> string uses the U+002F SOLIDUS character ("/") to denote directory hierarchy within the <a>temporary directory tree</a>. <a href="#fileConcept">Files</a>, like <a href="#directoryConcept">directories</a>, have distinct <a>name</a>s and <a>path</a>s which identify them on a <a>temporary directory tree</a>. </p>
<p> The top-most containing <a href="#directoryConcept">directory</a>, which contains all <a href="#directoryConcept">directories</a> and <a href="#fileConcept">files</a>, if any exist, is called the <dfn>root</dfn> <a href="#directoryConcept">directory</a>, and has the following properties:</p>
<ul>
<li><p>It is not contained by any other <a href="#directoryConcept">directory</a> in the <a>temporary directory tree</a>; it contains all others. It is the <em>root</em> of the <a>temporary directory tree</a>. </p></li>
<li><p>It is represented by a <a>path</a> that is equal to a single "/" U+002F SOLIDUS.</p>
</li>
<li><p>The <a href="#directoryConcept">directory</a> <em>from which</em> a user makes selections of <a href="#fileConcept">files</a> and <a href="#subdirectoryConcept">subdirectories</a> is considered an <a>immediate child</a> of the <a>root</a> of the <a>temporary directory tree</a> and has a <a>path</a> that is equal to a single "/" U+002F SOLIDUS concatenated with its name.</p>
<pre class="example highlight">
/**
The user picks items from a directory called 'music'
which is the top-most selection and an
immediate child of "/"
**/
console.log(selection.path);
// output is "/music"
</pre>
</li>
</ul>
</section>
<section>
<h3>The Temporary Directory Tree</h3>
<p>In this specification, a <dfn>temporary directory tree</dfn> consists of <a href="#directoryConcept">directories</a> and <a href="#fileConcept">file</a>s, along with the affiliated <a>path from root</a>, for each <a href="#directoryConcept">directory</a> and <a href="#fileConcept">file</a> that the user has selected from the underlying OS filesystem; each such <a href="#directoryConcept">directory</a> or <a href="#fileConcept">file</a> must correspond to a node in the <a>temporary directory tree</a>, with the top-most <a href="#directoryConcept">directory</a> being the <a href="#directoryConcept">directory</a> <em>from which</em> the user has made selections of <a href="#fileConcept">files</a> and <a href="#directoryConcept">directories</a>. </p>
<p>The <dfn>present working directory</dfn> is the node on the <a>temporary directory tree</a> that represents the current <a href="#directoryConcept">directory</a> from which an operation is taking place. In this specification, this is the <a href="#directoryConcept">directory</a> from which a <a><code>Directory</code></a> interface operation or attribute is called. </p>
<p>A <a>path</a> to a given <a href="#directoryConcept">directory</a> or <a href="#fileConcept">file</a> from the <a>root</a> <a href="#directoryConcept">directory</a> is said to be a <dfn>path from root</dfn> and starts with a leading "/" U+002F SOLIDUS character and ends with the name of the <a href="#fileConcept">file</a> or <a href="#directoryConcept">directory</a>. </p>
<pre class="example highlight">
/**
path from root of the 'jazz' directory, with 'music'
being the directory from which the user has made
selections of files and directories.
**/
console.log(currentSelection.path);
// output is "/music/genres/jazz";
console.log(currentSelection.name);
// output is "jazz"
</pre>
<p>A <dfn>child</dfn> is a node on the <a>temporary directory tree</a> with a position that is below a given position on the <a>temporary directory tree</a> for a given <a href="#directoryConcept">directory</a>; a <a href="#subdirectoryConcept">subdirectory</a> of the <a>present working directory</a> is a <a>child</a> of the <a>present working directory</a>; a <a href="#subdirectoryConcept">subdirectory</a> of <em>that</em> <a href="#subdirectoryConcept">subdirectory</a> is also a <a>child</a> of the <a>present working directory</a>. An <dfn>immediate child</dfn> corresponds to a node on the <a>temporary directory tree</a> that is either a <a href="#subdirectoryConcept">subdirectory</a> that is the next position on the <a>path</a>, or a <a href="#fileConcept">file</a> that is next on the <a>path</a>. A <dfn>parent</dfn> is a <a href="#directoryConcept">directory</a> that contains a <a href="#fileConcept">file</a> or another <a href="#directoryConcept">directory</a>; in particular, the <a href="#directoryConcept">directory</a> that contains the <a>present working directory</a> is its <a>parent</a>. The <a>root</a> <a href="#directoryConcept">directory</a> is the <a>parent</a> of all other nodes in the <a>temporary directory tree</a>.</p>
</section>
<section>
<h3>Returning Files and Directories</h3>
<p>When this specification says to <dfn>return a file or directory sequence promise</dfn> on a given <a>present working directory</a>, the user agent should run the following steps:</p>
<ol>
<li><p>If the result of running <a href="https://w3c.github.io/webappsec-secure-contexts/#settings-object">is settings object a secure context</a> with the <a href="https://html.spec.whatwg.org/multipage/webappapis.html#incumbent-settings-object">incumbent settings object</a> is <code>Not Secure</code>, return a new promise rejected with a "<code>SecurityError</code>" exception.</p></li>
<li><p>Let <var>p</var> be a new promise and <var>s</var> a sequence, initially set to an empty sequence.</p></li>
<li><p>Run the following steps asynchronously:</p>
<ol>
<li><p>If the <a>present working directory</a> has no <a href="#fileConcept">files</a> or <a href="#directoryConcept">directories</a>, resolve <var>p</var> with <var>s</var>, which is still an empty sequence.</p></li>
<li><p>Otherwise, for each <a>immediate child</a> of the <a>present working directory</a>, add the corresponding node to <var>s</var> as a <a><code>File</code></a> or <a>Directory</a> object, depending on the type of the <a>immediate child</a>.</p></li>
<li><p>If there are any problems retrieving any <a>immediate child</a>, reject <var>p</var> with an <code>InvalidStateError</code>.</p>
<div class="note"><p>Promise rejection occurs for any problem crawling the <a>present working directory</a>.</p></div>
</li>
<li><p>Once all the <a>immediate child</a> nodes of the <a>present working directory</a> have been added to <var>s</var> as a <a><code>File</code></a> or <a><code>Directory</code></a>, resolve <var>p</var> with <var>s</var>.</p></li>
</ol>
</li>
<li><p>Return <var>p</var>.</p></li>
</ol>
<div class="note"><p>A common method on both the <code>HTMLInputElement</code> and on the <code>Directory</code> interface called <code>getFilesAndDirectories()</code> returns <a href="#fileConcept">files</a> and <a href="#subdirectoryConcept">subdirectories</a> for a given <a href="#directoryConcept">directory</a> using the steps above. Each method invoking the steps above must specify what to consider as the <a>present working directory</a>. </p></div>
</section>
<section>
<h3>Triggering a Directory Picker</h3>
<p>When an <code>input</code> element's <code>type</code> attribute is in the <a>File Upload</a> state, the rules in this section apply [[!HTML]].</p>
<p>User agents may surface a directory picker, which may also serve as a file picker; this is an unspecified piece of user interface that a user agent may deploy, and may expand upon any existing user interface already in place for selecting files when the <code>input</code> element's <code>type</code> attribute is in the <a>File Upload</a> state. This generally happens synchronously and is considered a blocking operation. When this specification says to <dfn>trigger a directory picker</dfn> a user agent must follow the steps below (and may optionally follow the steps labeled "may" [[!RFC2119]]): </p>
<ol>
<li><p>If the result of running <a href="https://w3c.github.io/webappsec-secure-contexts/#settings-object">is settings object a secure context</a> with the <a href="https://html.spec.whatwg.org/multipage/webappapis.html#incumbent-settings-object">incumbent settings object</a> is <code>Not Secure</code>, the user agent must throw a <code>SecurityError</code> exception and additionally may prevent a directory picker from being shown at all. </p></li>
<li><p>If the user agent is capable of surfacing both a directory picker and a file picker in a single user interface element, this user agent is said to have a <dfn>Single File and Directory Picker</dfn>. This user agent must expose a value of <code>true</code> on the <a><code>isFilesAndDirectoriesSupported</code></a> attribute of the <a><code>HTMLInputElement</code></a>. </p>
<p>User agents in practice may reuse user interface elements from the host OS. If the host OS supports a <a>Single File and Directory Picker</a> a file input with a single button that enables the combined picker may be rendered and may resemble the suggested user interface element below:</p>
<figure>
<div style="border: 1px solid #999; color: #444; font-size: 14px; width: 285px; height: 20px; line-height: 20px; padding: 5px 5px 5px 10px; text-align: left;">
1 file selected.
<div style="float: right; width: 132.5px; height: 8px; line-height: 8px; padding: 5px; background-color: #eee; border: 1px solid #aaa; text-align: center;">Choose file(s)...</div>
</div>
<figcaption>Clicking "Choose file(s)" activates combined file & directory picker.</figcaption>
</figure>
<div class="note"><p>Currently, only OSX exposes a unified picker.</p></div>
</li>
<li><p>If the user agent does not have a <a>Single File and Directory Picker</a> it is said to have <dfn>Distinct File and Directory Pickers</dfn>. This user agent must expose a value of <code>false</code> on the <a><code>isFilesAndDirectoriesSupported</code></a> attribute of the <a><code>HTMLInputElement</code></a>.</p>
<p>If the user agent has <a>Distinct File and Directory Pickers</a>, possibly reusing user interface elements from the host OS, a file input that enables two separate pickers (file and directory) via two different buttons may be rendered and may resemble the suggested user interface element below:</p>
<figure>
<div style="border: 1px solid #999; color: #444; font-size: 14px; padding: 5px; width: 290px; height: 20px; line-height: 20px;">
<div style="float: left; width: 130px; height: 8px; line-height: 8px; padding: 5px; background-color: #eee; border: 1px solid #aaa; text-align: center;">Choose files...</div>
<div style="float: left; width: 130px; height: 8px; line-height: 8px; padding: 5px; background-color: #eee; border: 1px solid #aaa; text-align: center; margin-left: 5px;">Choose directories...</div>
</div>
<figcaption>Default (no selection)</figcaption>
</figure>
<figure>
<div style="border: 1px solid #999; color: #444; font-size: 14px; padding: 5px 5px 5px 10px; width: 285px; height: 20px; line-height: 20px; text-align: left;">
2 files selected.
<div style="float: right; height: 13px; line-height: 13px; padding: 5px; font-weight: bold; font-size: 16px; color: #999;">×</div>
</div>
<figcaption>After a selection has been made; clearing the field may reset it to <a href="#fig-default-no-selection"></a>.</figcaption>
</figure>
</li>
<li><p>If the user agent has <a>Distinct File and Directory Pickers</a> and is set to trigger in <dfn>Directory Picker Only</dfn> mode, it may only surface a picker that allows for directory picking, or it may surface a picker featuring two separate buttons as in <a href="#fig-default-no-selection">figure two above</a>. The suggested user interface element below may be used to surface an option to only pick directories:</p>
<figure>
<div style="border: 1px solid #999; color: #444; font-size: 14px; width: 285px; height: 20px; line-height: 20px; padding: 5px 5px 5px 10px; text-align: left;">
<div style="float: left; width: 132.5px; height: 8px; line-height: 8px; padding: 5px; background-color: #eee; border: 1px solid #aaa; text-align: center; margin-left: 5px;">Choose directories...</div>
</div>
<figcaption>Clicking "Choose directories..." activates a directory picker only.</figcaption>
</figure>
</li>
</ol>
</section>
</section>
<section>
<h2>Attributes</h2>
<div class="note"><p>This section will eventually be a pull request to the HTML specification.</p></div>
<p>When an <code>input</code> element's type attribute is in the <dfn>File Upload</dfn> state, the rules in this section apply [[!HTML]].</p>
<p>When the <code>input</code> element is in the <a>File Upload</a> state, it can represent two distinct types of user selections:
<ul>
<li><p>If the <a href="#directoryAttribute"><code>directory</code></a> attribute is NOT set, it represents a list of <em>only</em> the selected files, each file consisting of a file name, a file type, and a file body (the contents of the file). </p></li>
<li><p>If the <a href="#directoryAttribute"><code>directory</code></a> attribute is set, it represents a sequence of <em>both</em> the selections of files and <a href="#directoryConcept">directories</a>.</li></p>
</ul>
<p>The <dfn id="directoryAttribute"><code>directory</code></dfn> attribute is a boolean attribute [[!HTML]] that indicates whether a user is allowed the selection of both of <a href="#fileConcept">files</a> and <a href="#directoryConcept">directories</a>.</p>
</section>
<section>
<h2>APIs</h2>
<section>
<h2>Directory Interface</h2>
<p>The <a>Directory</a> interface represents a <a href="#directoryConcept">directory</a> on the <a>Directory Tree</a>. Methods and attributes on a <a>Directory</a> interface must act as if it is the <a>present working directory</a>.</p>
<pre class="idl">
[Exposed=(Window,Worker)]
interface Directory {
readonly attribute DOMString name;
readonly attribute DOMString path;
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
};
</pre>
<dfn>Directory.name</dfn>
<p>On getting, this attribute must return the name of the <a>present working directory</a>.</p>
<div class="issue"><p>We need normative language around characters that aren't allowed in a name; we also need to determine if
DOMString is sufficient.</p></div>
<dfn>Directory.path</dfn>
<p>On getting, this attribute must return the <a>path from root</a> of the <a>present working directory</a>, including its <a>name</a>.</p>
<pre class="example highlight">
// path of directory jazz
/music/genres/jazz
// path of file milesDavis.mp3
/music/genres/jazz/milesDavis.mp3
</pre>
<dfn>Directory.getFilesAndDirectories</dfn>
<p>When the <code>getFilesAndDirectories()</code> method is called, the user agent must <a>return a file or directory sequence promise</a> with this <a href="#directoryConcept">directory</a> as the <a>present working directory</a>.</p>
</section>
<section>
<h2>File Input</h2>
<p>More information about the <code>HTMLInputElement</code> interface can be found in the <a href="http://www.w3.org/html/wg/drafts/html/CR/forms.html#the-input-element">HTML5 spec</a>.</p>
<pre class="idl">
partial interface HTMLInputElement {
attribute boolean directory;
readonly attribute boolean isFilesAndDirectoriesSupported;
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
void chooseDirectory();
};
</pre>
<dfn>HTMLInputElement.directory</dfn>
<p>If the input <code>type</code> is "file" and the <a>HTMLInputElement.directory</a> attribute is set, the file input can accept directories in addition to files.
<div class="note">Adding the <code>multiple</code> attribute does not change the behavior, however, it allows older browsers to make the file input accept multiple files instead of just one since they would not recognize the <a>HTMLInputElement.directory</a> attribute.</div>
If this attribute is set, <code>input.files</code> MUST return <code>null</code>.
<div class="note">Due to this, <a>HTMLInputElement.getFilesAndDirectories</a> must be called to retrieve the chosen files and directories.</div>
<pre class="example highlight" title="HTML">
<input type="file" id="fileInput" directory multiple />
<!-- Supports being able to select multiple files and/or directories -->
<!-- Adding the multiple attribute is useful because older browsers would be able -->
<!-- to accept multiple files even if they do not recognize the directory attribute -->
</pre>
<p>The default click behavior of such a file input MUST trigger the file picker. Calling <a>HTMLInputElement.chooseDirectory</a> on the file input element MUST trigger the directory picker.</p>
<dfn>HTMLInputElement.isFilesAndDirectoriesSupported</dfn>
<p>On getting, this attribute must be <code>true</code> if the user agent will expose a <a>Single File and Directory Picker</a>, and <code>false</code> if the user agent will expose <a>Distinct File and Directory Pickers</a>.</p>
<dfn>HTMLInputElement.getFilesAndDirectories</dfn>
<p>When the <code>getFilesAndDirectories()</code> method is called, the user agent must run the steps below:</p>
<ol>
<li><p>Let <var>d</var> be the <a href="#directoryConcept">directory</a> on the underlying filesystem OS containing the user's selections of <a href="#fileConcept">files</a> and <a href="#directoryConcept">directories</a>. Set <var>d</var> to be the <a>present working directory</a> and an <a>immediate child</a> of the <a>root</a> <a href="#directoryConcept">directory</a> on the <a>temporary directory tree</a>. </p>
</li>
<li><p>Using <var>d</var> as the <a>present working directory</a> <a>return a file or directory sequence promise</a>.</p>
<div class="note">In order to retrieve all selections reliably, developers should call this method after the <code>change</code> event on <code>HTMLInputElement</code> has fired. Guidance in developer documentation here would be helpful.</div>
</li>
</ol>
<pre class="example highlight" title="JavaScript">
<!-- markup snippet might look like this -->
<input id='fileInput' type=file multiple directory
ondragover="alertLength(event);"
onchange="handleChangeEvent(event);">
// Within a script block we handle change event
function handleChangeEvent(e){
// change event fires on input element
var input = document.getElementById('fileInput');
if ('getFilesAndDirectories' in input) {
input.getFilesAndDirectories().then(function(filesAndDirs) {
// iterate through each item
// see drag and drop example below for more details
});
}
}
</pre>
<dfn>HTMLInputElement.chooseDirectory</dfn>
<p>When the <code>choseDirectory()</code> method is called, a user agent must <a>trigger a directory picker</a> in <a>Directory Picker Only</a> mode.</p>
<section>
<h2>Form Submission</h2>
<p>When a form is submitted with <code class="highlight">enctype="multipart/form-data"</code> and a file input with the <a>HTMLInputElement.directory</a> attribute (and a directory named "docs" was picked) it MUST adhere to the following pattern in its request payload:</p>
<div class="issue">TODO: generate form submission output from <a>temporary directory tree</a>.</div>
<pre class="example highlight">
------Boundary
Content-Disposition: form-data; name="file"; filename="/docs/1.txt"
Content-Type: text/plain
[DATA]
------Boundary
Content-Disposition: form-data; name="file"; filename="/docs/path/2.txt"
Content-Type: text/plain
[DATA]
------Boundary
Content-Disposition: form-data; name="file"; filename="/docs/path/to/3.txt"
Content-Type: text/plain
[DATA]
------Boundary--
</pre>
<p>
Directories that are empty MUST NOT be included in the request payload.
<div class="note">This will make it backwards compatible with server scripts that only expect files.</div>
</p>
</section>
</section>
<section>
<h2>Drag and Drop</h2>
<p>More information about the <code>DataTransfer</code> interface can be found in the <a href="http://www.w3.org/TR/2010/WD-html5-20101019/dnd.html#datatransfer">HTML5 spec</a>.</p>
<p><code>DataTransfer</code>'s <code>files</code> attribute MUST continue to work with no changes to its behavior.</p>
<pre class="idl">
partial interface DataTransfer {
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
};
</pre>
<dfn>DataTransfer.getFilesAndDirectories</dfn>
<p>When the <code>getFilesAndDirectories()</code> method is called, the user agent must run the steps below:</p>
<ol>
<li><p>Let <var>d</var> be the <a href="#directoryConcept">directory</a> on the underlying filesystem OS containing the user's selections of <a href="#fileConcept">files</a> and <a href="#directoryConcept">directories</a>. Set <var>d</var> to be the <a>present working directory</a> and an <a>immediate child</a> of the <a>root</a> <a href="#directoryConcept">directory</a> on the <a>temporary directory tree</a>. </p>
</li>
<li><p>Using <var>d</var> as the <a>present working directory</a> <a>return a file or directory sequence promise</a>.</p>
</li>
</ol>
<pre class="example highlight" title="JavaScript">
document.getElementById('dropDiv').addEventListener('drop', function(e) {
e.stopPropagation();
e.preventDefault();
var uploadFile = function(file, path) {
// handle file uploading
};
var iterateFilesAndDirs = function(filesAndDirs, path) {
for (var i = 0; i < filesAndDirs.length; i++) {
if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
var path = filesAndDirs[i].path;
// this recursion enables deep traversal of directories
filesAndDirs[i].getFilesAndDirectories().then(function(subFilesAndDirs) {
// iterate through files and directories in sub-directory
iterateFilesAndDirs(subFilesAndDirs, path);
});
} else {
uploadFile(filesAndDirs[i], path);
}
}
};
// begin by traversing the chosen files and directories
if ('getFilesAndDirectories' in e.dataTransfer) {
e.dataTransfer.getFilesAndDirectories().then(function(filesAndDirs) {
iterateFilesAndDirs(filesAndDirs, '/');
});
}
});
</pre>
</section>
</section>
<section class="informative">
<h2>Appendix</h2>
<section>
<h2>FAQ</h2>
<ol>
<li>Why did we use getFilesAndDirectories() instead of enumerate()?</li>
<ul>
<li>We want to be able to save the enumerate() name for the future when we have Observables available so that we can have enumerate() return an Observable.</li>
</ul>
<li>Why are we returning Promise for getFilesAndDirectories() instead of an Observable?</li>
<ul>
<li>The directory upload scenario does not require listening on changes to the file system, therefore Observables would not be warranted.</li>
<li>Observables, though undoubtedly advantageous in the enumeration scenario, are not well defined yet and it may take a long time before they are.</li>
<li>We want to build a solution using today's primitives (such as Promises) and then, if necessary, we can retrofit the API for future primitives (such as Observables) when they are available and well defined.</li>
</ul>
<li>Why are we returning an Array in the Promise?</li>
<ul>
<li>Provides a snapshot of the directories and files at the time that getFilesAndDirectories() is called. Developers would expect this for directory upload.</li>
<li>An array allows iterating through the File and Directory objects.</li>
</ul>
<li>Why did we remove enumerateDeep() from the originally proposed Directory interface?</li>
<ul>
<li>It is not needed for the time being as recursively calling the getFilesAndDirectories() function would fulfill the scenario that enumerateDeep() was meant to fulfill.</li>
<li>getFilesAndDirectories() would provide a smaller result set compared to enumerateDeep().</li>
</ul>
<li>Why is it ok to remove the other methods from the originally proposed Directory interface?</li>
<ul>
<li>Since the focus is on read-only scenarios to enable directory uploading, only a subset of the APIs are needed.</li>
<li>The Directory interface will be extensible for the future when we need to address scenarios that involve writing.</li>
</ul>
</ol>
</section>
</section>
</body>
</html>