Bug 769245 - Contacts API: Add ContactEmail Type. r=sicking

This commit is contained in:
Gregor Wagner 2012-07-03 11:00:53 -07:00
parent 79a6737a47
commit 96c377da98
7 changed files with 161 additions and 21 deletions

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"
"use strict";
/* static functions */
let DEBUG = 0;
@ -78,6 +78,29 @@ ContactAddress.prototype = {
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactAddress])
}
//ContactEmail
const CONTACTEMAIL_CONTRACTID = "@mozilla.org/contactEmail;1";
const CONTACTEMAIL_CID = Components.ID("{94811520-c11f-11e1-afa7-0800200c9a66}");
const nsIDOMContactEmail = Components.interfaces.nsIDOMContactEmail;
function ContactEmail(aType, aAddress) {
this.type = aType || null;
this.address = aAddress || null;
};
ContactEmail.prototype = {
classID : CONTACTEMAIL_CID,
classInfo : XPCOMUtils.generateCI({classID: CONTACTEMAIL_CID,
contractID: CONTACTEMAIL_CONTRACTID,
classDescription: "ContactEmail",
interfaces: [nsIDOMContactEmail],
flags: nsIClassInfo.DOM_OBJECT}),
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactEmail])
}
//ContactTelephone
const CONTACTTELEPHONE_CONTRACTID = "@mozilla.org/contactTelephone;1";
@ -133,10 +156,16 @@ Contact.prototype = {
init: function init(aProp) {
// Accept non-array strings for DOMString[] properties and convert them.
function _create(aField) {
if (typeof aField == "string")
return new Array(aField);
return aField;
function _create(aField) {
if (Array.isArray(aField)) {
for (let i = 0; i < aField.length; i++) {
if (typeof aField[i] !== "string")
aField[i] = String(aField[i]);
}
return aField;
} else if (aField != null) {
return [String(aField)];
}
};
this.name = _create(aProp.name) || null;
@ -146,7 +175,16 @@ Contact.prototype = {
this.familyName = _create(aProp.familyName) || null;
this.honorificSuffix = _create(aProp.honorificSuffix) || null;
this.nickname = _create(aProp.nickname) || null;
this.email = _create(aProp.email) || null;
if (aProp.email) {
aProp.email = Array.isArray(aProp.email) ? aProp.email : [aProp.email];
this.email = new Array();
for (let i = 0; i < aProp.email.length; i++)
this.email.push(new ContactEmail(aProp.email[i].type, aProp.email[i].address));
} else {
this.email = null;
}
this.photo = _create(aProp.photo) || null;
this.url = _create(aProp.url) || null;
this.category = _create(aProp.category) || null;
@ -445,4 +483,4 @@ ContactManager.prototype = {
}
const NSGetFactory = XPCOMUtils.generateNSGetFactory(
[Contact, ContactManager, ContactProperties, ContactAddress, ContactTelephone, ContactFindOptions])
[Contact, ContactManager, ContactProperties, ContactAddress, ContactTelephone, ContactFindOptions, ContactEmail])

View File

@ -7,6 +7,9 @@ contract @mozilla.org/contactAddress;1 {eba48030-89e8-11e1-b0c4-0800200c9a66}
component {82601b20-89e8-11e1-b0c4-0800200c9a66} ContactManager.js
contract @mozilla.org/contactTelephone;1 {82601b20-89e8-11e1-b0c4-0800200c9a66}
component {94811520-c11f-11e1-afa7-0800200c9a66} ContactManager.js
contract @mozilla.org/contactEmail;1 {94811520-c11f-11e1-afa7-0800200c9a66}
component {e31daea0-0cb6-11e1-be50-0800200c9a66} ContactManager.js
contract @mozilla.org/contactFindOptions;1 {e31daea0-0cb6-11e1-be50-0800200c9a66}

View File

@ -22,7 +22,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
const DB_NAME = "contacts";
const DB_VERSION = 2;
const DB_VERSION = 3;
const STORE_NAME = "contacts";
function ContactDB(aGlobal) {
@ -101,6 +101,31 @@ ContactDB.prototype = {
// Create new searchable indexes.
objectStore.createIndex("tel", "search.tel", { unique: false, multiEntry: true });
objectStore.createIndex("category", "properties.category", { unique: false, multiEntry: true });
} else if (currVersion == 2) {
debug("upgrade 2");
// Create a new scheme for the email field. We move from an array of emailaddresses to an array of
// ContactEmail.
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
// Delete old email index.
objectStore.deleteIndex("email");
// Upgrade existing email field in the DB.
objectStore.openCursor().onsuccess = function(event) {
let cursor = event.target.result;
if (cursor) {
debug("upgrade email1: " + JSON.stringify(cursor.value));
cursor.value.properties.email =
cursor.value.properties.email.map(function(address) { return { address: address }; });
cursor.update(cursor.value);
debug("upgrade email2: " + JSON.stringify(cursor.value));
cursor.continue();
}
};
// Create new searchable indexes.
objectStore.createIndex("email", "search.email", { unique: false, multiEntry: true });
}
}
},
@ -172,8 +197,16 @@ ContactDB.prototype = {
}
}
debug("lookup: " + JSON.stringify(contact.search[field]));
} else if (field == "email") {
let address = aContact.properties[field][i].address;
if (address && typeof address == "string") {
contact.search[field].push(address.toLowerCase());
}
} else {
contact.search[field].push(aContact.properties[field][i].toLowerCase());
let val = aContact.properties[field][i];
if (typeof val == "string") {
contact.search[field].push(val.toLowerCase());
}
}
}
}
@ -319,7 +352,9 @@ ContactDB.prototype = {
request = index.mozGetAll(options.filterValue, limit);
} else {
// not case sensitive
let tmp = options.filterValue.toLowerCase();
let tmp = typeof options.filterValue == "string"
? options.filterValue.toLowerCase()
: options.filterValue.toString().toLowerCase();
let range = this._global.IDBKeyRange.bound(tmp, tmp + "\uFFFF");
let index = store.index(key + "LowerCase");
request = index.mozGetAll(range, limit);

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"
"use strict";
let DEBUG = 0;
if (DEBUG)

View File

@ -76,7 +76,8 @@ var properties1 = {
givenName: ["Test1","Test2"],
nickname: "nicktest",
tel: [{type: "work", number: "123456"} , {type: "home", number: "+9-876-5432"}],
adr: adr1
adr: adr1,
email: [{type: "work", address: "x@y.com"}]
};
var properties2 = {
@ -88,7 +89,7 @@ var properties2 = {
additionalName: "dummyadditionalName",
nickname: "dummyNickname",
tel: [{type: "test", number: "123456789"},{type: "home", number: "234567890"}],
email: ["a@b.c", "b@c.d"],
email: [{type: "test", address: "a@b.c"}, {address: "b@c.d"}],
adr: [adr1, adr2],
impp: ["im1", "im2"],
org: ["org1", "org2"],
@ -148,6 +149,11 @@ function checkTel(tel1, tel2) {
checkStr(tel1.number, tel2.number, "Same number");
}
function checkEmail(email1, email2) {
checkStr(email1.type, email2.type, "Same type");
checkStr(email1.address, email2.address, "Same address");
}
function checkContacts(contact1, contact2) {
checkStr(contact1.name, contact2.name, "Same name");
checkStr(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
@ -156,7 +162,6 @@ function checkContacts(contact1, contact2) {
checkStr(contact1.familyName, contact2.familyName, "Same familyName");
checkStr(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStr(contact1.nickname, contact2.nickname, "Same nickname");
checkStr(contact1.email, contact2.email, "Same email");
checkStr(contact1.photo, contact2.photo, "Same photo");
checkStr(contact1.url, contact2.url, "Same url");
checkStr(contact1.category, contact2.category, "Same category");
@ -169,6 +174,8 @@ function checkContacts(contact1, contact2) {
is(contact1.sex, contact2.sex, "Same sex");
is(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
for (var i in contact1.email)
checkEmail(contact1.email[i], contact2.email[i]);
for (var i in contact1.adr)
checkAddress(contact1.adr[i], contact2.adr[i]);
for (var i in contact1.tel)
@ -269,6 +276,21 @@ var steps = [
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for exact email");
var options = {filterBy: ["email"],
filterOp: "equals",
filterValue: properties1.email[0].address};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
checkContacts(findResult1, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving by substring and update");
mozContacts.oncontactchange = function(event) {
@ -616,14 +638,14 @@ var steps = [
},
function () {
ok(true, "Modifying contact3");
findResult1.email = (properties1.nickname);
findResult1.email = [{address: properties1.nickname}];
findResult1.nickname = "TEST";
var newContact = new mozContact();
newContact.init(findResult1);
req = mozContacts.save(newContact);
req.onsuccess = function () {
var options = {filterBy: ["nickname", "email", "name"],
filterOp: "equals",
filterOp: "contains",
filterValue: properties1.nickname};
// One contact has it in nickname and the other in email
var req2 = mozContacts.find(options);
@ -741,7 +763,7 @@ var steps = [
ok(true, "Searching contacts by email");
var options = {filterBy: ["email"],
filterOp: "contains",
filterValue: properties2.email[0].substring(0, 4)};
filterValue: properties2.email[0].address.substring(0, 4)};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
@ -865,12 +887,12 @@ var steps = [
ok(true, "Testing clone contact2");
var cloned = new mozContact(createResult1);
ok(cloned.id != createResult1.id, "Cloned contact has new ID");
cloned.email = "new email!";
cloned.email = {address: "new email!"};
cloned.givenName = "Tom";
req = mozContacts.save(cloned);
req.onsuccess = function () {
ok(cloned.id, "The contact now has an ID.");
ok(cloned.email == "new email!", "Same Email");
ok(cloned.email.address == "new email!", "Same Email");
ok(createResult1.email != cloned.email, "Clone has different email");
ok(cloned.givenName == "Tom", "New Name");
next();
@ -892,7 +914,7 @@ var steps = [
function () {
ok(true, "Search with redundant fields should only return 1 contact");
createResult1 = new mozContact();
createResult1.init({name: "XXX", nickname: "XXX", email: "XXX", tel: {number: "XXX"}});
createResult1.init({name: "XXX", nickname: "XXX", email: [{address: "XXX"}], tel: {number: "XXX"}});
req = mozContacts.save(createResult1);
req.onsuccess = function() {
var options = {filterBy: [],
@ -1098,6 +1120,40 @@ var steps = [
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding empty contact");
createResult1 = new mozContact();
createResult1.init({givenName: 5});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test category search with equals");
var options = {filterBy: ["givenName"],
filterOp: "contains",
filterValue: 5};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "1 Entry.");
checkContacts(req.result[0], createResult1);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear()
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
clearTemps();

View File

@ -25,6 +25,13 @@ interface nsIDOMContactTelephone : nsISupports
attribute DOMString number;
};
[scriptable, uuid(94811520-c11f-11e1-afa7-0800200c9a66)]
interface nsIDOMContactEmail : nsISupports
{
attribute DOMString type;
attribute DOMString address;
};
[scriptable, uuid(e31daea0-0cb6-11e1-be50-0800200c9a66)]
interface nsIDOMContactFindOptions : nsISupports
{
@ -46,7 +53,7 @@ interface nsIDOMContactProperties : nsISupports
attribute jsval familyName; // DOMString[]
attribute jsval honorificSuffix; // DOMString[]
attribute jsval nickname; // DOMString[]
attribute jsval email; // DOMString[]
attribute jsval email; // ContactEmail[]
attribute jsval photo; // DOMString[]
attribute jsval url; // DOMString[]
attribute jsval category; // DOMString[]

View File

@ -519,6 +519,7 @@ var interfaceNamesInGlobalScope =
"WebGLActiveInfo",
"SVGGradientElement",
"ContactTelephone",
"ContactEmail",
"SVGFitToViewBox",
"SVGAElement"
]