Skip to content

Commit

Permalink
Merge pull request #26 from WICG/featuredetection
Browse files Browse the repository at this point in the history
Add feature detection & create the concept of a Contacts Source.
  • Loading branch information
rayankans authored Oct 2, 2019
2 parents ed5b514 + 1f21871 commit 391449d
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 89 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ dictionary ContactsSelectOptions {
[Exposed=(Window,SecureContext)]
interface ContactsManager {
Promise<sequence<ContactProperty>> getAvailableContactProperties();
Promise<sequence<ContactInfo>> select(sequence<ContactProperty> properties, optional ContactsSelectOptions options);
};
Expand Down
87 changes: 80 additions & 7 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ user's contacts every time they need it. This differs from some native contact A
necessary for ensuring users' contacts are not accessed without their knowledge and explicit
consent.

## Example ## {#example}
## Examples ## {#examples}

<div class="example">
Requesting contacts as a result of a user click.
Expand All @@ -65,6 +65,35 @@ consent.
is a developer-defined function.
</div>


<div class="example">
Requesting an address to deliver a gift to.

<pre class="lang-js">
selectRecipientButton.addEventListener('click', async () => {

// We are unsure if addresses are supported, or can be provided by the browser.
if ((await navigator.contacts.getAvailableContactProperties()).includes('address')) {
const contacts = await navigator.contacts.select(['address']);

if (!contacts.length) {
// Either no contacts were selected in the picker, or the picker could
// not be launched. Exposure of the API implies expected availability.
return;
}

// length is 1 since we didn't request multiple contacts.
sendGiftToAddress(contacts[0].address);
}

// Fallback to a form.
});
</pre>

In the above example `selectRecipientButton` is a {{HTMLButtonElement}}, and `sendGiftToAddress`
is a developer-defined function.
</div>

# Privacy Considerations # {#privacy}

Exposing contact information has a clear privacy impact, in terms of exposing PII of uninvolved
Expand Down Expand Up @@ -113,6 +142,21 @@ to each other.

A [=user contact=] contains data relating to a single user.

## Contacts source ## {#infrastructure-contacts-source}

The <dfn>contacts source</dfn> is a service that provides the user's contact information to
the user agent.

A [=contacts source=] consists of:
<div dfn-for="contacts source">

* <dfn>available contacts</dfn>, a [=list=] of [=user contacts=].
* <dfn>supported properties</dfn>, a [=list=] of [=available=] {{ContactProperty}} values.

</div>

Note: It is up to the user agent to choose the [=contacts source=].

</div>

# API Description # {#api}
Expand All @@ -136,11 +180,27 @@ The <dfn attribute>contacts</dfn> attribute's getter must return the [=context o

The [=browsing context=] has a <dfn>contact picker is showing flag</dfn>, initially unset.

## {{ContactsManager}} ## {#contacts-manager}
## {{ContactProperty}} ## {#contact-property}

<script type="idl">
enum ContactProperty { "address", "email", "name", "tel" };
</script>

A {{ContactProperty}} is considered to be <dfn>available</dfn> if its associated [=user contact=]
field can be accessed by the user agent.

: "address"
:: Associated with [=user contact=]'s [=user contact/addresses=].
: "email"
:: Associated with [=user contact=]'s [=user contact/emails=].
: "name"
:: Associated with [=user contact=]'s [=user contact/names=].
: "tel"
:: Associated with [=user contact=]'s [=user contact/numbers=].

## {{ContactsManager}} ## {#contacts-manager}

<script type="idl">
interface ContactAddress : PaymentAddress {};

dictionary ContactInfo {
Expand All @@ -156,12 +216,25 @@ dictionary ContactsSelectOptions {

[Exposed=(Window,SecureContext)]
interface ContactsManager {
Promise<sequence<ContactProperty>> getAvailableContactProperties();
Promise<sequence<ContactInfo>> select(sequence<ContactProperty> properties, optional ContactsSelectOptions options);
};
</script>

<div dfn-for="ContactsManager">

### {{ContactsManager/getAvailableContactProperties()}} ### {#contacts-manager-getavailablecontactproperties}

<div algorithm>
The <dfn method>getAvailableContactProperties()</dfn> method, when invoked, runs these steps:

1. Let |promise| be [=a new promise=].
1. Run the following steps [=in parallel=]:
1. Resolve |promise| with [=contacts source=]'s [=contacts source/supported properties=].
1. Return |promise|.

</div>

### {{ContactsManager/select()}} ### {#contacts-manager-select}

<div algorithm>
Expand All @@ -176,6 +249,9 @@ interface ContactsManager {
1. If |relevantBrowsingContext|'s [=contact picker is showing flag=] is set then return
[=a promise rejected with=] an {{InvalidStateError}} {{DOMException}}.
1. If |properties| is [=list/empty=], then return [=a promise rejected with=] a {{TypeError}}.
1. [=list/For each=] |property| of |properties|:
1. If [=contacts source=]'s [=contacts source/supported properties=] does not [=list/contain=]
|property|, then return [=a promise rejected with=] a {{TypeError}}.
1. Set |relevantBrowsingContext|'s [=contact picker is showing flag=].
1. Let |promise| be [=a new promise=].
1. Run the following steps [=in parallel=]:
Expand Down Expand Up @@ -213,8 +289,8 @@ interface ContactsManager {
[=boolean=]), and |properties| (a [=list=] of {{DOMString}}s), the user agent MUST present a user
interface that follows these rules:

* If presenting a user interface fails or accessing the source of the contact information fails,
then return failure.
* If presenting a user interface fails or accessing the [=contacts source=]'s
[=contacts source/available contacts=] fails, then return failure.
* The UI MUST prominently display the [=browsing context=]'s [=origin=].
* The UI MUST make it clear which `properties` of the contact will be shared.

Expand All @@ -227,6 +303,3 @@ interface ContactsManager {
* The UI MUST provide an a way for users to indicate that they are done selecting, in which case
remove the UI and return a [=list=] of the selected contacts as [=user contacts=].
</div>

Note: It is up to the user agent to choose the source of the contact information displayed in the
picker.
Loading

0 comments on commit 391449d

Please sign in to comment.