Skip to content

Commit 76eabad

Browse files
authored
Support file sharing (#53)
Web Share Target now allows targets to specify that they accept files. If a Web Share Target implementation does not support Web Share Target filtering on extension, then a criterion beginning with "." does not match any file. If a Web Share Target implementation does not support Web Share Target filtering on MIME type, then a criterion of the form type/subtype or type/* does not match any file. We specify that a implementation must support filtering on MIME types or filtering on file extensions, or both.
1 parent a5f4eb2 commit 76eabad

File tree

1 file changed

+259
-8
lines changed

1 file changed

+259
-8
lines changed

level-2/index.html

Lines changed: 259 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ <h2>
114114
<p>
115115
The <a data-link-for="ShareTarget">params</a> keys correspond to the
116116
key names in <a data-cite="WebShare#dom-sharedata">ShareData</a> from
117-
[[!WebShare]], while the values are arbitrary names that will be used
118-
as query parameters when the target is launched.
117+
[[WebShare]], while the values are arbitrary names that will be used as
118+
query parameters when the target is launched.
119119
</p>
120120
<p>
121121
When a share takes place, if the user selects this share target, the
@@ -208,6 +208,44 @@ <h2>
208208
})());
209209
});
210210
</pre>
211+
<p>
212+
A <a data-link-for="ShareTargetParams">files</a> entry in params is
213+
used to declare that files are accepted by the share target:
214+
</p>
215+
<pre class="example json" title="manifest.webmanifest">
216+
{
217+
"name": "Aggregator",
218+
"share_target": {
219+
"action": "/cgi-bin/aggregate",
220+
"method": "POST",
221+
"enctype": "multipart/form-data",
222+
"params": {
223+
"title": "name",
224+
"text": "description",
225+
"url": "link",
226+
"files": [
227+
{
228+
"name": "records",
229+
"accept": ["text/csv", ".csv"]
230+
},
231+
{
232+
"name": "graphs",
233+
"accept": "image/svg+xml"
234+
}
235+
]
236+
}
237+
}
238+
}
239+
</pre>
240+
<p>
241+
The target will be <a>invoked</a> with a
242+
<code>multipart/form-data</code> POST request, with field names as
243+
specified in params. Each shared file is assigned to the first files
244+
entry that accepts its MIME type. (The <code>"POST"</code>
245+
<code>method</code> and <code>"multipart/form-data"</code>
246+
<code>enctype</code> are necessary when file sharing, as with HTML
247+
forms.)
248+
</p>
211249
<p>
212250
How the handler deals with the shared data is at the handler's
213251
discretion, and will generally depend on the type of app. Here are some
@@ -216,14 +254,16 @@ <h2>
216254
<ul>
217255
<li>An email client might draft a new email, using <code>title</code>
218256
as the subject of an email, with <code>text</code> and <code>url</code>
219-
concatenated together as the body.
257+
concatenated together as the body, and <code>files</code> as
258+
attachments.
220259
</li>
221260
<li>A social networking app might draft a new post, ignoring
222261
<code>title</code>, using <code>text</code> as the body of the message
223-
and adding <code>url</code> as a link. If <code>text</code> is missing,
224-
it might use <code>url</code> in the body as well. If <code>url</code>
225-
is missing, it might scan <code>text</code> looking for a URL and add
226-
that as a link.
262+
and adding <code>url</code> as a link. Image <code>files</code> would
263+
be accepted by MIME type or file extension, and attached to the post.
264+
If <code>text</code> is missing, it might use <code>url</code> in the
265+
body as well. If <code>url</code> is missing, it might scan
266+
<code>text</code> looking for a URL and add that as a link.
227267
</li>
228268
<li>A text messaging app might draft a new message, ignoring
229269
<code>title</code> and using <code>text</code> and <code>url</code>
@@ -241,10 +281,16 @@ <h2>
241281
"!appmanifest#dom-webappmanifest">WebAppManifest</dfn> dictionary.
242282
</p>
243283
<pre class="idl">
284+
dictionary ShareTargetFiles {
285+
required USVString name;
286+
(USVString or sequence&lt;USVString&gt;) accept = [];
287+
};
288+
244289
dictionary ShareTargetParams {
245290
USVString title;
246291
USVString text;
247292
USVString url;
293+
(ShareTargetFiles or sequence&lt;ShareTargetFiles&gt;) files;
248294
};
249295

250296
dictionary ShareTarget {
@@ -322,6 +368,70 @@ <h3>
322368
warning</a> that the enctype is not supported, and return
323369
<code>undefined</code>.
324370
</li>
371+
<li>If <var>share target</var>["<a data-link-for=
372+
"ShareTarget">params</a>"]["<a data-link-for=
373+
"ShareTargetParams">files</a>"] is a <a>ShareTargetFiles</a>
374+
dictionary, <var>bucket</var>, set <var>share
375+
target</var>["<a data-link-for=
376+
"ShareTarget">params</a>"]["<a data-link-for=
377+
"ShareTargetParams">files</a>"] to [<var>bucket</var>].
378+
</li>
379+
<li>If <var>share target</var>["<a data-link-for=
380+
"ShareTarget">params</a>"]["<a data-link-for=
381+
"ShareTargetParams">files</a>"] contains one or more
382+
<a>ShareTargetFiles</a> dictionaries, and <var>share
383+
target</var>["<a data-link-for="ShareTarget">method</a>"] is not an
384+
<a data-cite="!INFRA#ascii-case-insensitive">ASCII
385+
case-insensitive</a> match for the string <code>"POST"</code>, or
386+
<var>share target</var>["<a data-link-for="ShareTarget">enctype</a>"]
387+
is not an <a data-cite="!INFRA#ascii-case-insensitive">ASCII
388+
case-insensitive</a> match for the string
389+
<code>"multipart/form-data"</code>, <a data-cite=
390+
"!appmanifest#dfn-issue-a-developer-warning">issue a developer
391+
warning</a> that files are only supported with multipart/form-data
392+
POST, and return <code>undefined</code>.
393+
</li>
394+
<li>For each <var>bucket</var> in <var>share
395+
target</var>["<a data-link-for=
396+
"ShareTarget">params</a>"]["<a data-link-for=
397+
"ShareTargetParams">files</a>"]:
398+
<ol>
399+
<li>If <var>bucket</var>["<a data-link-for=
400+
"ShareTargetFiles">name</a>"] is an empty string, <a data-cite=
401+
"!appmanifest#dfn-issue-a-developer-warning">issue a developer
402+
warning</a> and return <code>undefined</code>.
403+
</li>
404+
<li>If <var>bucket</var>["<a data-link-for=
405+
"ShareTargetFiles">accept</a>"] is a <a data-cite=
406+
"!WEBIDL#idl-USVString">USVString</a>, <var>accept</var>, set
407+
<var>bucket</var>["<a data-link-for=
408+
"ShareTargetFiles">accept</a>"] to [<var>accept</var>].
409+
</li>
410+
<li>If <var>bucket</var>["<a data-link-for=
411+
"ShareTargetFiles">accept</a>"] contains a string that does not
412+
match any of the following, <a data-cite=
413+
"!appmanifest#dfn-issue-a-developer-warning">issue a developer
414+
warning</a> and return <code>undefined</code>.
415+
<ul>
416+
<li>a string whose first character is a U+002E FULL STOP
417+
character (.)
418+
</li>
419+
<li>
420+
<var>type</var><code>/</code><var>subtype</var> (where
421+
<var>type</var> and <var>subtype</var> are <a data-cite=
422+
"!RFC7230#section-3.2.6">RFC7230 tokens</a>)
423+
</li>
424+
<li>
425+
<var>type</var><code>/*</code> (where <var>type</var> is a
426+
<a data-cite="!RFC7230#section-3.2.6">RFC7230 token</a>)
427+
</li>
428+
<li>
429+
<code>*/*</code>
430+
</li>
431+
</ul>
432+
</li>
433+
</ol>
434+
</li>
325435
<li>Let <var>action</var> be the result of <a data-cite=
326436
"!URL#concept-url-parser">parsing</a> the <a data-cite=
327437
"!URL#concept-url">URL</a> <var>share
@@ -408,6 +518,30 @@ <h3>
408518
The <dfn>url</dfn> member specifies the name of the query parameter
409519
used for the URL string referring to a resource being shared.
410520
</p>
521+
<p>
522+
The <dfn>files</dfn> member contains zero or more
523+
<a>ShareTargetFiles</a> dictionaries.
524+
</p>
525+
</section>
526+
<section data-dfn-for="ShareTargetFiles" data-link-for=
527+
"ShareTargetFiles">
528+
<h3>
529+
<code>ShareTargetFiles</code> and its members
530+
</h3>
531+
<p>
532+
The <dfn>ShareTargetFiles</dfn> dictionary contains the following
533+
members.
534+
</p>
535+
<p>
536+
The <dfn>name</dfn> member specifies the name of the form field used
537+
to share the files.
538+
</p>
539+
<p>
540+
The <dfn>accept</dfn> member specifies a sequence of accepted MIME
541+
type(s) or file extension(s), the latter expressed as strings
542+
starting with U+002E FULL STOP (.). An empty sequence indicates that
543+
all files are accepted.
544+
</p>
411545
</section>
412546
</section>
413547
<section>
@@ -456,6 +590,25 @@ <h2>
456590
visited or explicitly registered.
457591
</p>
458592
<div class="issue" data-number="26"></div>
593+
<p>
594+
An implementation supports <dfn>filtering on MIME types</dfn> if it
595+
takes into account the MIME types of the files being shared when
596+
presenting the user with a choice of share targets.
597+
</p>
598+
<p>
599+
An implementation supports <dfn>filtering on file extensions</dfn> if
600+
it takes into account the extensions in the names of the files being
601+
shared when presenting the user with a choice of share targets.
602+
</p>
603+
<p>
604+
An implementation MUST support <a>filtering on MIME types</a> or
605+
<a>filtering on file extensions</a>, or both.
606+
</p>
607+
<p>
608+
If a file being shared is not <a>accepted</a> by any of a share
609+
target's <a data-link-for="ShareTargetParams">files</a> entries, the
610+
user MUST NOT be presented with that web share target as an option.
611+
</p>
459612
</section>
460613
<section>
461614
<h2>
@@ -538,7 +691,9 @@ <h3>
538691
"ShareTarget">action</a>"].
539692
</li>
540693
<li>Let <var>entry list</var> be a new empty list of name-value
541-
tuples.
694+
tuples. Each value can be either a <a data-cite=
695+
"!WEBIDL#idl-USVString">USVString</a> or a <a data-cite=
696+
"!FILE-API#file-section">File</a> list.
542697
</li>
543698
<li>For each <var>member</var> in the sequence «
544699
<code>"title"</code>, <code>"text"</code>, <code>"url"</code> »,
@@ -561,6 +716,56 @@ <h3>
561716
</li>
562717
</ol>
563718
</li>
719+
<li>Let <var>accepted</var> be an empty map of
720+
name/<code><a data-cite="!FILE-API#file-section">File</a></code> list
721+
pairs.
722+
</li>
723+
<li>For each <var>bucket</var> in the sequence
724+
<var>manifest</var>["<a>share_target</a>"]["<a data-link-for=
725+
"ShareTarget">params</a>"]["<a data-link-for=
726+
"ShareTargetParams">files</a>"],
727+
<ol>
728+
<li>Set
729+
<var>accepted</var>[<var>bucket</var>["<a data-link-for="ShareTargetFiles">name</a>"]]
730+
to a new empty <code><a data-cite=
731+
"!FILE-API#file-section">File</a></code> list.
732+
</li>
733+
</ol>
734+
</li>
735+
<li>For each <var>shared file</var> in the sequence
736+
<var>data</var>[<code>"files"</code>],
737+
<ol>
738+
<li>Find the first <var>bucket</var> in the sequence
739+
<var>manifest</var>["<a>share_target</a>"]["<a data-link-for=
740+
"ShareTarget">params</a>"]["<a data-link-for=
741+
"ShareTargetParams">files</a>"] that <a>accepts</a> <var>shared
742+
file</var>.
743+
</li>
744+
<li>Append <var>shared file</var> to
745+
<var>accepted</var>[<var>bucket</var>["<a data-link-for=
746+
"ShareTargetFiles">name</a>"]].
747+
</li>
748+
</ol>
749+
</li>
750+
<li>For each <var>bucket</var> in the sequence
751+
<var>manifest</var>["<a>share_target</a>"]["<a data-link-for=
752+
"ShareTarget">params</a>"]["<a data-link-for=
753+
"ShareTargetParams">files</a>"],
754+
<ol>
755+
<li>Let <var>name</var> be the value of
756+
<var>bucket</var>["<a data-link-for=
757+
"ShareTargetFiles">name</a>"].
758+
</li>
759+
<li>Let <var>value</var> be the value of
760+
<var>accepted</var>[<var>name</var>], a (possibly empty)
761+
<code><a data-cite="!FILE-API#file-section">File</a></code> list.
762+
</li>
763+
<li>
764+
<a data-cite="!INFRA#list-append">Append</a> to <var>entry
765+
list</var> a tuple with <var>name</var> and <var>value</var>.
766+
</li>
767+
</ol>
768+
</li>
564769
<li>Let <var>header list</var> be a new empty <a data-cite=
565770
"!FETCH/#concept-header-list">header list</a>.
566771
</li>
@@ -648,6 +853,52 @@ <h3>
648853
run on it and still has a <a>share_target</a> afterwards.
649854
</p>
650855
</section>
856+
<section>
857+
<h3>
858+
Determining if a file is accepted
859+
</h3>
860+
<p>
861+
The algorithm for determining if a <a>ShareTargetFiles</a>
862+
<var>bucket</var> <dfn data-lt="accepted">accepts</dfn> a
863+
<a data-cite="!FILE-API#file-section">File</a> <var>shared file</var>
864+
is as follows:-
865+
</p>
866+
<ol>
867+
<li>If <var>bucket</var>["<a data-link-for=
868+
"ShareTargetFiles">accept</a>"] is empty, return <code>true</code>.
869+
</li>
870+
<li>For each <var>criterion</var> in
871+
<var>bucket</var>["<a data-link-for="ShareTargetFiles">accept</a>"]:
872+
<ol>
873+
<li>If the first character of <var>criterion</var> is a U+002E
874+
FULL STOP character (.) and <var>shared
875+
file</var>[<code>"name"</code>] ends with <var>criterion</var>,
876+
and the implementation supports <a>filtering on file
877+
extensions</a>, return <code>true</code>.
878+
</li>
879+
<li>If <var>criterion</var> is
880+
<var>type</var><code>/</code><var>subtype</var> (where
881+
<var>type</var> and <var>subtype</var> are <a data-cite=
882+
"!RFC7230#section-3.2.6">RFC7230 tokens</a>) and matches the MIME
883+
type of <var>shared file</var>, and the implementation supports
884+
<a>filtering on MIME types</a>, return <code>true</code>.
885+
</li>
886+
<li>If <var>criterion</var> is <var>type</var><code>/*</code>
887+
(where <var>type</var> is a <a data-cite=
888+
"!RFC7230#section-3.2.6">RFC7230 token</a>) and the MIME type of
889+
<var>shared file</var> is a subtype of <code>type</code>, and the
890+
implementation supports <a>filtering on MIME types</a>, return
891+
<code>true</code>.
892+
</li>
893+
<li>If <var>criterion</var> is <code>*/*</code>, return
894+
<code>true</code>.
895+
</li>
896+
</ol>
897+
</li>
898+
<li>Return <code>false</code>.
899+
</li>
900+
</ol>
901+
</section>
651902
</section>
652903
<section class="informative">
653904
<h2>

0 commit comments

Comments
 (0)