-
Notifications
You must be signed in to change notification settings - Fork 63
/
index.html
792 lines (788 loc) · 32.1 KB
/
index.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
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
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>
Web Share API
</title>
<script src="https://www.w3.org/Tools/respec/respec-w3c" class=
"remove"></script>
<script class='remove'>
var respecConfig = {
shortName: "web-share",
previousMaturity: "FPWD",
specStatus: "ED",
github: {
repoURL: "w3c/web-share",
branch: "main"
},
testSuiteURI: "https://wpt.live/web-share/",
group: "webapps",
editors: [{
name: "Matt Giuca",
company: "Google Inc.",
companyURL: "https://google.com",
w3cid: 91260
},
{
name: "Eric Willigers",
company: "Google Inc.",
companyURL: "https://google.com",
w3cid: 67534
},
{
name: "Marcos Cáceres",
company: "Apple Inc.",
companyURL: "https://apple.com",
w3cid: 39125,
}],
caniuse: {
feature: "web-share",
browsers: ["chrome", "firefox", "safari", "edge", "and_chr", "and_ff", "ios_saf"],
},
xref: "web-platform",
mdn: true,
// The Wylecial breaks the link checker with bad HTTP code response, so disabling this for now.
// localBiblio: {
// "Wylecial": {
// "date": "2020-08-25",
// "title": "Stealing local files using Safari Web Share API",
// "Author": "Pawel Wylecial",
// "href": "https://blog.redteam.pl/2020/08/stealing-local-files-using-safari-web.html"
// }
// }
};
</script>
</head>
<body data-cite="FILEAPI">
<section id="abstract">
<p>
This specification defines an API for sharing text, links and other
content to an arbitrary destination of the user's choice.
</p>
<p>
The available share targets are not specified here; they are provided
by the user agent. They could, for example, be apps, websites or
contacts.
</p>
</section>
<section id="sotd">
<p>
This is a work in progress. Wide review and feedback welcome.
</p>
</section>
<section class="informative">
<h2>
Usage Examples
</h2>
<h3>
Sharing text and links
</h3>
<p>
This example shows a basic share operation. In response to a button
click, this JavaScript code shares the current page's URL.
</p>
<pre class="example javascript" title="Sharing text and URL">
shareButton.addEventListener("click", async () => {
try {
await navigator.share({ title: "Example Page", url: "" });
console.log("Data was shared successfully");
} catch (err) {
console.error("Share failed:", err.message);
}
});
</pre>
<p>
Note that a {{ShareData/url}} of `''` refers to the current page URL,
just as it would in a link. Any other absolute or relative URL can also
be used.
</p>
<p>
In response to this call to {{Navigator/share()}}, the user agent would
display a picker or chooser dialog, allowing the user to select a
target to share this title and the page URL to.
</p>
<h3>
Sharing a file
</h3>
<p>
This example shows how to share a file. Note that the
{{ShareData/files}} member is an array, allowing for multiple files to
be shared.
</p>
<pre class="example javascript" title="Sharing a file">
shareButton.addEventListener("click", async () => {
const file = new File(data, "some.png", { type: "image/png" });
try {
await navigator.share({
title: "Example File",
files: [file]
});
} catch (err) {
console.error("Share failed:", err.message);
}
});
</pre>
<h3>
Validating a share
</h3>
<p>
Calling {{Navigator/canShare()}} method with a {{ShareData}} dictionary
[=validate share data|validates=] the shared data. Unlike
{{Navigator/share()}}, it can be called without [=transient
activation=].
</p>
<pre class="js example">
const file = new File([], "some.png", { type: "image/png" });
// Check if files are supported
if (navigates.canShare({files: [file]})) {
// Sharing a png file would probably be ok...
}
// Check if a URL is ok to share...
if (navigates.canShare({ url: someURL })) {
// The URL is valid and can probably be shared...
}
</pre>
<h3>
Checking if members are supported
</h3>
<p>
Because of how WebIDL dictionaries work, members passed to
{{Navigator/share(())}} that are unknown to the user agent are ignored.
This can be a problem when sharing multiple members, but the user agent
doesn't support sharing one of those members. To be sure that every
member being passed is supported by the user agent, you can pass them
to {{Navigator/canShare()}} individually to check if they are
supported.
</p>
<pre class="js example" title="Future-proofing shares">
const data = {
title: "Example Page",
url: "https://example.com",
text: "This is a text to share",
someFutureThing: "some future thing",
};
const allSupported = Object.entries(data).every(([key, value]) => {
return navigator.canShare({ [key]: value });
});
if (allSupported) {
await navigator.share(data);
}
</pre>
<p>
Alternatively, you can adjust application's UI to not show UI
components for unsupported members.
</p>
<pre class="js example" title="Filtering out unsupported members">
const data = {
title: "Example Page",
url: "https://example.com",
text: "This is a text to share",
someFutureThing: "some future thing",
};
// Things that are not supported...
const unsupported = Object.entries(data).filter(([key, value]) => {
return !navigator.canShare({ [key]: value });
});
</pre>
</section>
<section>
<h2>
API definition
</h2>
<section data-dfn-for="Navigator">
<h3>
Extensions to the `Navigator` interface
</h3>
<pre class="idl">
partial interface Navigator {
[SecureContext] Promise<undefined> share(optional ShareData data = {});
[SecureContext] boolean canShare(optional ShareData data = {});
};
</pre>
<p>
User agents that do not support sharing SHOULD NOT expose
{{Navigator/share()}} on the {{Navigator}} interface.
</p>
<div class="note">
The above statement is designed to permit feature detection. If
{{Navigator/share()}} is present, there is a reasonable expectation
that it will work and present the user with at least one <a>share
target</a>. Clients can use the presence or absence of this method to
determine whether to show UI that triggers its use.
</div>
<section>
<h4>
Internal Slots
</h4>
<p>
This API adds the following internal slot to the {{Navigator}}
interface.
</p>
<dl>
<dt>
{{Promise}}? <dfn>[[\sharePromise]]</dfn>
</dt>
<dd>
The [=this=].{{Navigator/[[sharePromise]]}} is a promise that
represents a user's current intent to share some data with a
<a>share target</a>. It is initialized to `null`.
</dd>
</dl>
</section>
<section>
<h4>
<dfn>share()</dfn> method
</h4>
<p>
When the {{Navigator/share()}} method is called with argument
|data:ShareData|, run the following steps:
</p>
<ol class="algorithm">
<li>Let |document:Document| be the [=current settings object=]'s
[=relevant global object=]'s [=associated `Document`=].
</li>
<li>If |document| is not [=Document/fully active=], return [=a
promise rejected with=] an {{"InvalidStateError"}}
{{DOMException}}.
</li>
<li>If |document| is not <a>allowed to use</a> <a>"web-share"</a>,
return [=a promise rejected with=] a {{"NotAllowedError"}}
{{DOMException}}.
</li>
<li>If [=this=].{{Navigator/[[sharePromise]]}} is not `null`,
return [=a promise rejected with=] an {{"InvalidStateError"}}
{{DOMException}}.
</li>
<li>Let |global:Window| be [=this=]'s [=relevant global object=].
</li>
<li>If |global| does not have [=transient activation=], return [=a
promise rejected with=] a {{"NotAllowedError"}} {{DOMException}}.
</li>
<li>[=Consume user activation=] of |global|.
</li>
<li>Let |base:URL| be [=this=]'s <a>relevant settings object</a>'s
[=environment settings object/API base URL=].
</li>
<li>If [=validate share data=] with |data| and |base| returns
false, then return [=a promise rejected with=] a {{TypeError}}.
</li>
<li>If |data|'s {{ShareData/url}} member is present:
<ol>
<li>Let |url:URL| be the result of running the <a>URL
parser</a> on |data|'s {{ShareData/url}} with |base|.
</li>
<li>Assert: |url| is {{URL}}.
</li>
<li>Set |data| to a copy of |data|, with its {{ShareData/url}}
member set to the result of running the <a>URL serializer</a>
on |url|.
</li>
</ol>
</li>
<li>If a file type is being blocked due to security considerations,
return [=a promise rejected with=] a {{"NotAllowedError"}}
{{DOMException}}.
</li>
<li>Set [=this=].{{Navigator/[[sharePromise]]}} to be <a>a new
promise</a>.
</li>
<li>Return [=this=].{{Navigator/[[sharePromise]]}} and <a>in
parallel</a>:
<ol>
<li>If there are no <a>share targets</a> available, [=queue a
global task=] on the [=user interaction task source=] using
|global| to:
<ol>
<li>[=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with
an {{"AbortError"}} {{DOMException}}.
</li>
<li>Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
</li>
<li>Abort these steps.
</li>
</ol>
</li>
<li>Present the user with a choice of one or more <a>share
targets</a>, selected at the user agent's discretion. The user
MUST be given the option to cancel rather than choosing any of
the share targets. Wait for the user's choice.
</li>
<li>If the user chose to cancel the share operation, [=queue a
global task=] on the [=user interaction task source=] using
|global| to:
<ol>
<li>[=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with
an {{"AbortError"}} {{DOMException}},
</li>
<li>Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
</li>
<li>Abort these steps.
</li>
</ol>
</li>
<li>Activate the chosen <a>share target</a>, <a>convert |data|
to a format suitable for ingestion into the target</a>, and
transmit the converted data to the target.
</li>
<li>If an error occurs starting the target or transmitting the
data, [=queue a global task=] on the [=user interaction task
source=] using |global| to:
<ol>
<li>[=Reject=] [=this=].{{Navigator/[[sharePromise]]}} with
an {{"DataError"}} {{DOMException}}.
</li>
<li>Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
</li>
<li>Abort these steps.
</li>
</ol>
</li>
<li>Once the data has either been successfully transmitted to
the [=share target=], or successfully transmitted to the OS (if
the transmission to the [=share target=] cannot be confirmed),
[=queue a global task=] on the [=user interaction task source=]
using |global| to:
<ol>
<li>[=Resolve=] [=this=].{{Navigator/[[sharePromise]]}}
with `undefined`.
</li>
<li>Set [=this=].{{Navigator/[[sharePromise]]}} to `null`.
</li>
</ol>
</li>
</ol>
</li>
</ol>
<p>
The user agent MUST NOT allow the website to learn which share
targets are available, or the identity of the chosen target.
</p>
<div class="note">
{{Navigator/share()}} always shows some form of UI, to give the
user a choice of application and get their approval to invoke and
send data to a potentially native application (which carries a
security risk). For this reason, user agents are prohibited from
showing any kind of "always use this target in the future" option,
or bypassing the UI if there is only a single share target.
</div>
</section>
<section>
<h3>
`canShare(data)` method
</h3>
<p>
When the <dfn>canShare()</dfn> method is called with argument
{{ShareData}} |data:ShareData|, run the following steps:
</p>
<ol class="algorithm">
<li>Let |document:Document| be the [=current settings object=]'s
[=relevant global object=]'s [=associated `Document`=].
</li>
<li>If |document| is not [=Document/fully active=], return false.
</li>
<li>If |document| is not <a>allowed to use</a> <a>"web-share"</a>,
return false.
</li>
<li>Return the result of [=validate share data=] with |data| and
[=this=]'s [=relevant settings object=]'s [=environment settings
object/API base URL=].
</li>
</ol>
</section>
<section>
<h3>
Validate share data
</h3>
<p>
To <dfn>validate share data</dfn> with |data:ShareData| and
|base:URL|, run the following steps:
</p>
<ol class="algorithm">
<li>If none of |data|'s members {{ShareData/title}},
{{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are
present, return false.
</li>
<li>Let |titleTextOrUrl:boolean| be true if any of
{{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is
present.
</li>
<li>If |data|'s {{ShareData/files}} member is present:
<ol>
<li>If |titleTextOrUrl| is false and |data|'s
{{ShareData/files}} member is empty, return false.
<p class="note">
This causes a `{ files: [] }` dictionary to be treated as
an empty dictionary. However, passing a dictionary like
`{text: "text", files: []}` is fine, as `files` is just
ignored.
</p>
</li>
<li>If the implementation does not support file sharing, return
false.
</li>
<li>If the user agent believes sharing any of the files in
`files` would result in a potentially hostile share, return
false.
</li>
</ol>
</li>
<li>If |data|'s {{ShareData/url}} member is present:
<ol>
<li>Let |url:URL| be the result of running the [=URL parser=]
on |data|'s {{ShareData/url}} member, with |base|, and no
encoding override.
</li>
<li>If |url| is failure, return false.
</li>
<li>
<p>
If |url| is a URL the user agent deems potentially hostile
(e.g., "file:") or wouldn't make sense to outside the scope
of the document (e.g., "blob:"), return false.
</p>
<aside class="issue" data-number="178"></aside>
</li>
</ol>
</li>
<li>Return true.
</li>
</ol>
</section>
</section>
<section data-dfn-for="ShareData">
<h3>
`ShareData` dictionary
</h3>
<pre class="idl">
dictionary ShareData {
sequence<File> files;
USVString title;
USVString text;
USVString url;
};
</pre>
<p>
The <dfn>ShareData</dfn> dictionary consists of several optional
members:
</p>
<dl data-sort="">
<dt>
<dfn>files</dfn> member
</dt>
<dd>
Files to be shared.
</dd>
<dt>
<dfn>title</dfn> member
</dt>
<dd>
The title of the document being shared. May be ignored by the
target.
</dd>
<dt>
<dfn>text</dfn> member
</dt>
<dd>
Arbitrary text that forms the body of the message being shared.
</dd>
<dt>
<dfn>url</dfn> member
</dt>
<dd>
A URL string referring to a resource being shared.
</dd>
</dl>
<div class="note">
These members are {{USVString}} (as opposed to {{DOMString}}) because
they are not allowed to contain surrogate code points. Among other
things, this means that the user agent can serialize them into any
Unicode encoding, such as <a data-cite="rfc3629#section-3">UTF-8</a>,
without change or loss of data or the generation of replacement
characters.
</div>
<div class="note">
The {{ShareData/url}} member can contain a <a>relative-URL
string</a>. In this case, it will be automatically resolved relative
to the current page location, just like a {{HTMLBaseElement/href}} on
an [^a^] element, before being given to the share target.
</div>
</section>
</section>
<section>
<h2>
Share targets
</h2>
<p>
A <dfn data-export="">share target</dfn> is the abstract concept of a
destination that the user agent will transmit the share data to. What
constitutes a share target is at the discretion of the user agent.
</p>
<p>
A share target might not be directly able to accept a {{ShareData}}
(due to not having been written with this API in mind). However, it
MUST have the ability to receive data that matches some or all of the
concepts exposed in {{ShareData}}. To <dfn>convert data to a format
suitable for ingestion into the target</dfn>, the user agent SHOULD map
the members of {{ShareData}} onto equivalent concepts in the target. It
MAY discard or combine members if necessary. The meaning of each member
of the payload is at the discretion of the share target.
</p>
<div class="note">
Mapping the {{ShareData}} to the share target's (or operating system's)
native format can be tricky as some platforms will not have an
equivalent set of members. For example, if the target has a "text"
member but not a "URL" member (as is the case on Android), one solution
is to concatenate both the {{ShareData/text}} and {{ShareData/url}}
members of {{ShareData}} and pass the result in the "text" member of
the target.
</div>
<p>
Each share target MAY be made conditionally available depending on the
{{ShareData}} payload delivered to the {{Navigator/share()}} method.
</p>
<div class="note">
Once a share target has been given the payload, the share is considered
successful. If the target considers the data unacceptable or an error
occurs, it can either recover gracefully, or show an error message to
the end-user; it cannot rely on the sender to handle errors. In other
words, the {{Navigator/share()}} method is "fire and forget"; it does
not wait for the target to approve or reject the payload.
</div>
<section class="informative">
<h3>
Examples of share targets
</h3>
<p>
The list of share targets can be populated from a variety of sources,
depending on the user agent and host operating system. For example:
</p>
<ul>
<li>Built-in service (e.g., "copy to clipboard").
</li>
<li>Native applications written for the host operating system.
</li>
<li>Contacts (e.g., the user agent directly shares to a person from
the user's address book, using a specific app).
</li>
<li>Websites (e.g., the user agent fills in a template URL with the
members of the {{ShareData}}, then navigates to that URL in a new
browsing context).
</li>
</ul>
<div class="note">
There is an attempt to standardize the registration of websites to
receive share data for that final use case; see <a href=
"https://github.com/w3c/web-share-target">Web Share Target</a>.
</div>
<p>
In some cases, the host operating system will provide a sharing or
intent system similar to Web Share. In these cases, the user agent
can simply forward the share data to the operating system and not
talk directly to native applications.
</p>
</section>
</section>
<section id="permissions-policy" data-cite="permissions-policy">
<h2>
Permissions Policy integration
</h2>
<p>
This specification defines a policy-controlled permission identified by
the string <code><dfn class="permission">"web-share"</dfn></code>. Its
<a>default allowlist</a> is '`self`'.
</p>
<div class="note">
<p>
A <a>document</a>’s permission policy determines whether a
{{Navigator/share()}} call immediately rejects with a
{{"NotAllowedError"}} {{DOMException}}.
</p>
</div>
</section>
<section class="informative">
<h2>
Accessibility considerations
</h2>
<p>
When this specification is used to present information in the user
interface, implementors will want to follow the OS level accessibility
guidelines for the platform.
</p>
</section>
<section class="informative" data-cite="secure-contexts">
<h2>
Security and privacy considerations
</h2>
<p>
Web Share enables data to be sent from websites to native applications.
While this ability is not unique to Web Share, it does come with a
number of potential security issues that can vary in severity
(depending on the underlying platform).
</p>
<ul>
<li>There is a requirement to not allow the website to learn which apps
are installed, or which app was chosen from {{Navigator/share()}},
because this information could be used for fingerprinting, as well as
leaking details about the user's device.
</li>
<li>Implementors will want to carefully consider what information is
revealed in the error message when {{Navigator/share()}} is rejected.
Even distinguishing between the case where no targets are available and
user cancellation could reveal information about which apps are
installed on the user's device.
</li>
<li>There is a requirement that {{Navigator/share()}} presents the user
with a dialog asking them to select a target application (even if there
is only one possible target). This surface serves as a security
confirmation, ensuring that websites cannot silently send data to
native applications.
</li>
<li>Due to the capabilities of the API surface, {{Navigator/share()}}
is only [=exposed=] in [=secure contexts=] (such as `https://`
schemes).
</li>
<li>Developers can use the means afforded by the
[[[permissions-policy]]] specification to control if and when a
third-party context is [=allowed to use=] this API.
</li>
<li>Use of {{Navigator/share()}} from a <a href=
"https://en.wikipedia.org/wiki/Privacy_mode">private browsing mode</a>
might leak private data to a third-party application that does not
respect the user's privacy setting. User agents could present
additional warnings or disable the feature entirely when in a private
browsing mode, but this is not mandated as the chooser UI could be
considered sufficient warning.
</li>
<li>The data passed to {{Navigator/share()}} might be used to exploit
buffer overflow or other remote code execution vulnerabilities in
native applications that receive shares. There is no general way to
guard against this, but implementors will want to be aware that it is a
possibility.
</li>
<li>
<p>
Share targets that dereference a shared URL and forward that
information on might inadvertently forward information that might
be otherwise confidential. This can lead to unexpected information
leakage if shares reference content that is only accessible by that
application, the host on which it runs, or its network location.
</p>
<p>
Malicious sites might exploit share targets that leak information
by providing URLs that ultimately resolve to local resources,
including, but not limited to, "file:" URLs or local services that
might otherwise be inaccessible. Even though this API limits shared
URLS to "http:" and "https:", use of redirects to other URLs or
tweaks to DNS records for hosts in those URLs might be used to
cause applications to acquire content.
</p>
<p>
To avoid being used in these attacks, share targets can consume the
URL, retrieve the content, and process that information without
sharing it. For instance, a photo editing application might
retrieve an image that is "shared" with it. A share target can also
share the URL without fetching any of the referenced content.
</p>
<p>
Share targets that fetch content for the purposes of offering a
preview or for sharing content risk information leakage. Content
that is previewed and authorized by a user might be safe to
forward, however it is not always possible for a person to identify
when information should be confidential, so forwarding any content
presents a risk. In particular, the {{ShareData/title}} might be
used by an attacker to trick a user into misinterpreting the nature
of the content. <!--
, as demonstrated in the [[Wylecial]] <a data-cite=
"Wylecial#">proof of concept attack</a>
-->
</p>
</li>
</ul>
</section>
<section class="appendix informative">
<h2>
Extensibility of this API
</h2>
<p>
The Web Share API is designed to be extended in the future by way of
new members added to the {{ShareData}} dictionary, to allow both
sharing of new types of data (<i>e.g.</i>, <a href=
"https://github.com/w3c/web-share/issues/12">images</a>) and strings
with new semantics (<i>e.g.</i> author).
</p>
<div class="warning">
This doesn't mean user agents can add whatever members they like. It
means that new members can be added to the standard in the future.
</div>
<p>
The three members {{ShareData/title}}, {{ShareData/text}}, and
{{ShareData/url}}, are part of the base feature set, and
implementations that provide {{Navigator/share()}} need to accept all
three. Any new members that are added in the future will be
<em>individually feature-detectable</em>, to allow for
backwards-compatibility with older implementations that don't recognize
those members. These new members might also be added as optional "MAY"
requirements.
</p>
<div class="note">
There is <a href="https://github.com/heycam/webidl/issues/107">an open
discussion</a> about how to provide feature-detection for dictionary
members. Web Share will use the mechanism produced by that discussion.
</div>
<p>
The {{Navigator/share()}} method returns a rejected promise with a
{{TypeError}} if none of the specified members are present. The
intention is that when a new member is added, it will also be added to
this list of recognized members. This is for future-proofing
implementations: if a web site written against a future version of this
spec uses <em>only</em> new members (<i>e.g.</i>,
`navigator.share({image: x})`), it will be valid in future user agents,
but a {{TypeError}} on user agents implementing an older version of the
spec. Developers will be asked to feature-detect any new members they
rely on, to avoid having errors surface in their program.
</p>
<p>
Editors of this spec will want to carefully consider the genericity of
any new members being added, avoiding members that are closely
associated with a particular service, user agent or operating system,
in favour of members that can potentially be applied to a wide range of
platforms and targets.
</p>
</section>
<section id="conformance"></section>
<section id="idl-index"></section>
<section class="informative">
<h2>
Changlog
</h2>
<script class="remove">
const ignoredHashes = [
"2ed0b468aacf7a4e3e351f25f114e9cb2fbef009"
];
function removeCommits(entry) {
const { message, hash } = entry;
for (const ignoredHash of ignoredHashes) {
if (ignoredHash.startsWith(hash)) {
return false;
};
}
return !/^editorial|^chore|^\[chore|^fix|^refactor|^tests?|^docs|^typo|^nit/i.test(message);
}
</script> <rs-changelog from="1589731080e09b9c7d485e54340ba66bc3ae1be0"
filter="removeCommits"></rs-changelog>
</section>
<section class="appendix">
<h2>
Acknowledgments
</h2>
<p>
Thanks to the <a href="https://www.w3.org/TR/web-intents">Web
Intents</a> team, who laid the groundwork for the web app
interoperability use cases. In particular, <a href=
"https://paul.kinlan.me/">Paul Kinlan</a>, who did a lot of early
advocacy for Web Share.
</p>
</section>
</body>
</html>