Bug 909224 - "Want to add the phonetic name of the name to mozContacts". r=reuben

This commit is contained in:
Teiichiro Fukuda 2014-04-07 03:14:00 +02:00
parent 4059919385
commit e1629be6ef
5 changed files with 422 additions and 2 deletions

View File

@ -29,6 +29,7 @@ const CONTACTS_SENDMORE_MINIMUM = 5;
// Keep in sync with the interfaces.
const PROPERTIES = [
"name", "honorificPrefix", "givenName", "additionalName", "familyName",
"phoneticGivenName", "phoneticFamilyName",
"honorificSuffix", "nickname", "photo", "category", "org", "jobTitle",
"bday", "note", "anniversary", "sex", "genderIdentity", "key", "adr", "email",
"url", "impp", "tel"

View File

@ -22,7 +22,7 @@ Cu.importGlobalProperties(["indexedDB"]);
/* all exported symbols need to be bound to this on B2G - Bug 961777 */
this.DB_NAME = "contacts";
this.DB_VERSION = 19;
this.DB_VERSION = 20;
this.STORE_NAME = "contacts";
this.SAVED_GETALL_STORE_NAME = "getallcache";
const CHUNK_SIZE = 20;
@ -169,6 +169,10 @@ ContactDB.prototype = {
objectStore.createIndex("category", "properties.category", { multiEntry: true });
objectStore.createIndex("email", "search.email", { multiEntry: true });
objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
aDb.createObjectStore(SAVED_GETALL_STORE_NAME);
aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
}
@ -705,6 +709,17 @@ ContactDB.prototype = {
next();
},
function upgrade19to20() {
if (DEBUG) debug("upgrade19to20 create schema(phonetic)");
if (!objectStore) {
objectStore = aTransaction.objectStore(STORE_NAME);
}
objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
objectStore.createIndex("phoneticGivenNameLowerCase", "search.phoneticGivenName", { multiEntry: true });
next();
},
];
let index = aOldVersion;
@ -824,6 +839,8 @@ ContactDB.prototype = {
tel: [],
exactTel: [],
parsedTel: [],
phoneticFamilyName: [],
phoneticGivenName: [],
};
for (let field in aContact.properties) {
@ -1115,6 +1132,21 @@ ContactDB.prototype = {
}, null, aErrorCb);
},
getSortByParam: function CDB_getSortByParam(aFindOptions) {
switch (aFindOptions.sortBy) {
case "familyName":
return [ "familyName", "givenName" ];
case "givenName":
return [ "givenName" , "familyName" ];
case "phoneticFamilyName":
return [ "phoneticFamilyName" , "phoneticGivenName" ];
case "phoneticGivenName":
return [ "phoneticGivenName" , "phoneticFamilyName" ];
default:
return [ "givenName" , "familyName" ];
}
},
/*
* Sorting the contacts by sortBy field. aSortBy can either be familyName or givenName.
* If 2 entries have the same sortyBy field or no sortBy field is present, we continue
@ -1125,7 +1157,7 @@ ContactDB.prototype = {
return;
if (aFindOptions.sortBy != "undefined") {
const sortOrder = aFindOptions.sortOrder;
const sortBy = aFindOptions.sortBy == "familyName" ? [ "familyName", "givenName" ] : [ "givenName" , "familyName" ];
const sortBy = this.getSortByParam(aFindOptions);
aResults.sort(function (a, b) {
let x, y;

View File

@ -90,6 +90,8 @@ var properties1 = {
name: ["Test1 TestFamilyName", "Test2 Wagner"],
familyName: ["TestFamilyName","Wagner"],
givenName: ["Test1","Test2"],
phoneticFamilyName: ["TestphoneticFamilyName1","TestphoneticFamilyName2"],
phoneticGivenName: ["TestphoneticGivenName1","TestphoneticGivenName2"],
nickname: ["nicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
@ -100,6 +102,8 @@ var properties2 = {
name: ["dummyHonorificPrefix dummyGivenName dummyFamilyName dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyFamilyName"],
givenName: ["dummyGivenName"],
phoneticFamilyName: ["dummyphoneticFamilyName"],
phoneticGivenName: ["dummyphoneticGivenName"],
honorificPrefix: ["dummyHonorificPrefix","dummyHonorificPrefix2"],
honorificSuffix: ["dummyHonorificSuffix"],
additionalName: ["dummyadditionalName"],
@ -120,6 +124,86 @@ var properties2 = {
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
// To test sorting(CJK)
var c9 = {
phoneticFamilyName: ["a"],
phoneticGivenName: ["a"],
};
var c10 = {
phoneticFamilyName: ["b"],
phoneticGivenName: ["b"],
};
var c11 = {
phoneticFamilyName: ["c","a","b"],
phoneticGivenName: ["c","a","b"],
};
var c12 = {
phoneticFamilyName: ["c","a","c"],
phoneticGivenName: ["c","a","c"],
};
var c13 = {
phoneticFamilyName: [],
phoneticGivenName: [],
};
var c14 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c15 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var c16 = {
phoneticFamilyName: ["e","e","e"],
phoneticGivenName: ["e","e","e"],
};
var properties3 = {
// please keep capital letters at the start of these names
name: ["Taro Yamada", "Ichiro Suzuki"],
familyName: ["Yamada","Suzuki"],
givenName: ["Taro","Ichiro"],
phoneticFamilyName: ["TestPhoneticFamilyYamada","TestPhoneticFamilySuzuki"],
phoneticGivenName: ["TestPhoneticGivenTaro","TestPhoneticGivenIchiro"],
nickname: ["phoneticNicktest"],
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}, {type: ["home"], value: "+49 451 491934"}],
adr: [adr1],
email: [{type: ["work"], value: "x@y.com"}],
};
var properties4 = {
name: ["dummyHonorificPrefix dummyTaro dummyYamada dummyHonorificSuffix", "dummyHonorificPrefix2"],
familyName: ["dummyYamada"],
givenName: ["dummyTaro"],
phoneticFamilyName: ["dummyTestPhoneticFamilyYamada"],
phoneticGivenName: ["dummyTestPhoneticGivenTaro"],
honorificPrefix: ["dummyPhoneticHonorificPrefix","dummyPhoneticHonorificPrefix2"],
honorificSuffix: ["dummyPhoneticHonorificSuffix"],
additionalName: ["dummyPhoneticAdditionalName"],
nickname: ["dummyPhoneticNickname"],
tel: [{type: ["test"], value: "7932012345", carrier: "myCarrier", pref: 1},{type: ["home", "custom"], value: "7932012346", pref: 0}],
email: [{type: ["test"], value: "a@b.c"}, {value: "b@c.d", pref: 1}],
adr: [adr1, adr2],
impp: [{type: ["aim"], value:"im1", pref: 1}, {value: "im2"}],
org: ["org1", "org2"],
jobTitle: ["boss", "superboss"],
note: ["test note"],
category: ["cat1", "cat2"],
url: [{type: ["work", "work2"], value: "www.1.com", pref: 1}, {value:"www2.com"}],
bday: new Date("1980, 12, 01"),
anniversary: new Date("2000, 12, 01"),
sex: "male",
genderIdentity: "test",
key: ["ERPJ394GJJWEVJ0349GJ09W3H4FG0WFW80VHW3408GH30WGH348G3H"]
};
var sample_id1;
var sample_id2;
@ -265,6 +349,8 @@ function checkContacts(contact1, contact2) {
checkStrArray(contact1.givenName, contact2.givenName, "Same givenName");
checkStrArray(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStrArray(contact1.familyName, contact2.familyName, "Same familyName");
checkStrArray(contact1.phoneticFamilyName, contact2.phoneticFamilyName, "Same phoneticFamilyName");
checkStrArray(contact1.phoneticGivenName, contact2.phoneticGivenName, "Same phoneticGivenName");
checkStrArray(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStrArray(contact1.nickname, contact2.nickname, "Same nickname");
checkCategory(contact1.category, contact2.category);

View File

@ -745,6 +745,8 @@ var steps = [
name: [],
familyName: [],
givenName: [],
phoneticFamilyName: [],
phoneticGivenName: [],
nickname: [],
tel: [],
adr: [],
@ -825,6 +827,301 @@ var steps = [
};
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact");
createResult1 = new mozContact(properties3);
req = 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, "Adding a new contact2");
createResult2 = new mozContact(properties4);
req = mozContacts.save(createResult2);
req.onsuccess = function () {
ok(createResult2.id, "The contact now has an ID.");
sample_id2 = createResult2.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({sortBy: "phoneticFamilyName"});
req.onsuccess = function () {
is(req.result.length, 2, "Found exactly 2 contact.");
checkContacts(req.result[1], properties3);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Searching contacts by query1");
var options = {filterBy: ["phoneticGivenName", "email"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)}
req = mozContacts.find(options)
req.onsuccess = function () {
is(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, "Searching contacts by query2");
var options = {filterBy: ["phoneticGivenName", "email"],
filterOp: "startsWith",
filterValue: properties4.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
is(findResult1.adr.length, 2, "Adr length 2");
checkContacts(findResult1, createResult2);
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Adding 20 contacts");
for (var i=0; i<19; i++) {
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
};
req.onerror = onFailure;
};
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkStrArray(createResult1.name, properties3.name, "Same Name");
checkCount(20, "20 contacts in DB", next);
};
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find(defaultOptions);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts2");
var options = {filterBy: ["phoneticGivenName"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
checkContacts(createResult1, req.result[19]);
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts3");
var options = {filterBy: ["phoneticGivenName", "tel", "email"],
filterOp: "startsWith",
filterValue: properties3.phoneticGivenName[0].substring(0, 3)};
req = mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 20, "20 Entries.");
checkContacts(createResult1, req.result[10]);
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Testing clone contact");
createResult1 = new mozContact(properties3);
req = mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkStrArray(createResult1.phoneticFamilyName, properties3.phoneticFamilyName, "Same phoneticFamilyName");
checkStrArray(createResult1.phoneticGivenName, properties3.phoneticGivenName, "Same phoneticGivenName");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "Retrieving all contacts");
req = mozContacts.find({sortBy: "phoneticGivenName"});
req.onsuccess = function () {
is(req.result.length, 1, "1 Entries.");
next();
}
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c11);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c11, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c10);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c10, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c12);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c12, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c9);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c9, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "ascending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 4, "4 results");
checkContacts(req.result[0], c9);
checkContacts(req.result[1], c10);
checkContacts(req.result[2], c11);
checkContacts(req.result[3], c12);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "descending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 4, "4 results");
checkContacts(req.result[0], c12);
checkContacts(req.result[1], c11);
checkContacts(req.result[2], c10);
checkContacts(req.result[3], c9);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c13);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c13, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting with empty string");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "ascending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 5, "5 results");
checkContacts(req.result[0], c13);
checkContacts(req.result[1], c9);
checkContacts(req.result[2], c10);
checkContacts(req.result[3], c11);
checkContacts(req.result[4], c12);
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c15);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c15, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c14);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c14, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Test sorting");
createResult1 = new mozContact(c16);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
checkContacts(c16, createResult1);
next();
};
req.onerror = onFailure;
},
function () {
// Android does not support published/updated fields. Skip this.
if (isAndroid) {
next();
return;
}
ok(true, "Test sorting with published");
var options = {sortBy: "phoneticFamilyName",
sortOrder: "descending"};
req = navigator.mozContacts.find(options);
req.onsuccess = function () {
is(req.result.length, 3, "3 results");
ok(req.result[0].published < req.result[1].published, "Right sorting order");
ok(req.result[1].published < req.result[2].published, "Right sorting order");
next();
};
req.onerror = onFailure;
},
clearDatabase,
function () {
ok(true, "all done!\n");
SimpleTest.finish();

View File

@ -44,8 +44,10 @@ dictionary ContactProperties {
sequence<DOMString>? name;
sequence<DOMString>? honorificPrefix;
sequence<DOMString>? givenName;
sequence<DOMString>? phoneticGivenName;
sequence<DOMString>? additionalName;
sequence<DOMString>? familyName;
sequence<DOMString>? phoneticFamilyName;
sequence<DOMString>? honorificSuffix;
sequence<DOMString>? nickname;
sequence<DOMString>? category;
@ -81,8 +83,10 @@ interface mozContact {
[Cached, Pure] attribute sequence<DOMString>? name;
[Cached, Pure] attribute sequence<DOMString>? honorificPrefix;
[Cached, Pure] attribute sequence<DOMString>? givenName;
[Cached, Pure] attribute sequence<DOMString>? phoneticGivenName;
[Cached, Pure] attribute sequence<DOMString>? additionalName;
[Cached, Pure] attribute sequence<DOMString>? familyName;
[Cached, Pure] attribute sequence<DOMString>? phoneticFamilyName;
[Cached, Pure] attribute sequence<DOMString>? honorificSuffix;
[Cached, Pure] attribute sequence<DOMString>? nickname;
[Cached, Pure] attribute sequence<DOMString>? category;