WebAPI/ContactsAPI
Contacts API specification
The DAP WG (W3C) has specification sharing this proposal goal [1]. For the moment, the Contacts API proposal might or might not look like the DAP specification.
Goals
Provide DOM API access to the device address book, and the contacts contained therein with a simple minimal API that has a high-degree of interoperability with both device address books and commonly published web contact information (vCard/hCard). - Tantek
Status
See bug 674720.
Proposed API
There is an object in window.navigator named mozContacts with the following interface:
interface ContactsManager { void find(in ContactFindOptions options, in ContactFindSuccessCallback successCB, in ContactErrorCallback errorCB); Contact create(in ContactProperties properties); void clear(in ContactSuccessCallback successCB, in ContactErrorCallback errorCB); };
interface ContactFindOptions : nsISupports { attribute DOMString filterValue; // e.g. "Tom" attribute DOMString filterOp; // e.g. "contains" attribute DOMString[] filterBy; // e.g. "givenName" };
interface ContactFindSuccessCallback { void handleEvent([array, size_is(count)] in Contact contacts, in unsigned long count); };
TO DO: Research/document device-specific address book capabilities and represent using methods on the ContactsManager interface.
The following Contact interface is based vCard4/hCard properties, flattened for the simple/typical case of one address (adr) based on the microformats 2.0 hCard iteration.
interface ContactAddress { attribute DOMString streetAddress; attribute DOMString locality; attribute DOMString region; attribute DOMString postalCode; attribute DOMString countryName; attribute double latitude; attribute double longitude; attribute double altitude; };
interface ContactProperties { attribute DOMString[] name; attribute DOMString[] honorificPrefix; attribute DOMString[] givenName; attribute DOMString[] additionalName; attribute DOMString[] familyName; attribute DOMString[] honorificSuffix; attribute DOMString[] nickname; attribute DOMString[] email; attribute DOMString[] photo; attribute DOMString[] url; attribute DOMString[] category; attribute ContactAddress[] adr; attribute DOMString[] tel; attribute DOMString[] org; attribute Date bday; attribute DOMString[] note; attribute DOMString[] impp; /* per RFC 4770, included in vCard4 */ attribute Date anniversary; /* new in vCard4 */ attribute DOMString sex; /* new in vCard4, gender sub-component 1 */ attribute DOMstring gender-identity'; /* new in vCard4, gender sub-comp 2 */ };
interface ContactWriter : ContactProperties { readonly attribute DOMString id; readonly attribute Date published; readonly attribute Date updated; };
interface Contact : ContactWriter { void save(in ContactSuccessCallback successCb, in ContactErrorCallback errorCb); void remove(in ContactSuccessCallback successCb, in ContactErrorCallback errorCb); Contact clone(); };
Note: despite hCard2 including a flat set of adr properties into the top level h-card object for ease of publishing, this interface always abstracts those properties into a ContactAddress sub-object for simplicity (smaller/cleaner) of interface. The interface is able to represent published data.
Notes of properties left out from vCard4/hCard(2), why the above is a subset of vCard4/hCard(2). Some common reasons:
- NU - Not commonly used in practice, either in address books or in publishing on the web. Reconsider such properties if usage changes.
- ER - Error prone whenever entered/published. Such properties are toast. Not getting added.
- AB - Absent from typical device address books (if you've seen a specific device with such fields in the address book, please list it here as a nested list item, preferably with screenshot of the UI). Reconsider such properties if added to address book UIs, note such research/data accordingly in #Considered_changes section below.
Specific deliberately omitted property notes:
- 'logo' - NU, 'photo' is used instead
- 'post-office-box' - NU, AB
- 'extended-address' - ER. in practice such data typically ends up in a long 'street-address'.
- 'organization-name' and 'organization-unit' are rarely separately specified, users/publishers preferring to use the simple flat 'org' property instead.
Added for B2G db (but not in any known existing device address books):
- ContactAddress 'geo' property components 'latitude', 'longitude' and additional 'altitude' from GeoLocation API
- Contact 'gender' property components 'sex', 'gender-identity' (from vCard4/hCard2 in particular)
Considered changes
- mozContacts object might move to window.navigator.device;
- more Contact attributes (from Address Book UIs of BlackBerry - BB, iPhone/iTouch - iOS)
- ringtone (BB, iOS)
- job-title (BB, iOS)
- messagetone (BB)
- phonetic-given-name (iOS)
- phonetic-family-name (iOS)
- formal-name (per suggestion from Jonas), like name, but with all "honorable so and so" etc. included as you would formally address or introduce someone. needs examples of publication on the web, and/or device address books that actually include such a field (haven't seen one yet).
FAQ
Why are givenName familyName arrays instead of optional
- could use clarification of why a number of fields are arrays instead of optional DOMString. e.g. givenName, familyName. Those seem like 0-or-1 cases, not lists.
Why are flattened adr properties arrays instead of optional
- could use clarification of why a number of fields are arrays instead of optional DOMString. e.g. fields of the flattened adr. Those seem like 0-or-1 cases, not lists.
- In short, simplification and i18n. The multivalued adr properties are a result of both lack of use / common mis-use of post-office-box and extended-address properties (such data is more often/reliably shoved into multiple lines of street-address) and countries having multiple lines/values for street-address and/or locality/region. - Tantek 10:37, 25 October 2011 (PDT)
Example
function errorCb(contactError) { alert("Error: " + contactError.code); };
function findCb(contacts) { for (var i=0; i<contacts.length; i++) { alert("Contact found: " + contacts[0].givenName); } };
function successCb() { alert("Success"); };
let newContact = navigator.mozContacts.create({givenName: "Tom"}); newContact.save(function(){alert("Contact saved")}, errorCb); navigator.mozContacts.find({}, findCb, errorCb); // return all Contacts navigator.mozContacts.find({filterValue: "Tom", filterOp: "contains", filterBy: "givenName"}, findCb, errorCb); let otherContact = newContact.clone(); otherContact.givenName = "Tim"; otherContact.save(successCb, errorCb); navigator.mozContacts.find({}, findCb, errorCb); newContact.remove(successCb, errorCb); navigator.mozContacts.clear(successCb, errorCb);