From 73c890014f1486e3206d90b1f85ed9c17b7cf29e Mon Sep 17 00:00:00 2001 From: Gregor Wagner Date: Mon, 2 Apr 2012 16:39:57 -0700 Subject: [PATCH] Bug 734198 - Contacts API: Add Sorting. r=bent --- dom/contacts/ContactManager.js | 19 +-- dom/contacts/fallback/ContactDB.jsm | 12 +- dom/contacts/fallback/ContactService.jsm | 17 ++ dom/contacts/tests/test_contacts_basics.html | 156 ++++++++++++++++++ .../contacts/nsIDOMContactProperties.idl | 2 + 5 files changed, 188 insertions(+), 18 deletions(-) diff --git a/dom/contacts/ContactManager.js b/dom/contacts/ContactManager.js index ad60be2c2191..cd7efd9938a4 100644 --- a/dom/contacts/ContactManager.js +++ b/dom/contacts/ContactManager.js @@ -19,7 +19,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/DOMRequestHelper.jsm"); -XPCOMUtils.defineLazyGetter(Services, "rs", function() { +XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() { return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService); }); @@ -79,16 +79,7 @@ const CONTACTFINDOPTIONS_CONTRACTID = "@mozilla.org/contactFindOptions;1"; const CONTACTFINDOPTIONS_CID = Components.ID("{e31daea0-0cb6-11e1-be50-0800200c9a66}"); const nsIDOMContactFindOptions = Components.interfaces.nsIDOMContactFindOptions; -function ContactFindOptions(aFilterValue, aFilterBy, aFilterOp, aFilterLimit) { - this.filterValue = aFilterValue || ''; - - this.filterBy = new Array(); - for (let field in aFilterBy) - this.filterBy.push(field); - - this.filterOp = aFilterOp || ''; - this.filterLimit = aFilterLimit || 0; -}; +function ContactFindOptions() { }; ContactFindOptions.prototype = { @@ -282,7 +273,7 @@ ContactManager.prototype = { if (req) { let result = this._convertContactsArray(contacts); debug("result: " + JSON.stringify(result)); - Services.rs.fireSuccess(req, result); + Services.DOMRequest.fireSuccess(req, result); } else { debug("no request stored!" + msg.requestID); } @@ -292,7 +283,7 @@ ContactManager.prototype = { case "Contact:Remove:Return:OK": req = this.getRequest(msg.requestID); if (req) - Services.rs.fireSuccess(req, null); + Services.DOMRequest.fireSuccess(req, null); break; case "Contacts:Find:Return:KO": case "Contact:Save:Return:KO": @@ -300,7 +291,7 @@ ContactManager.prototype = { case "Contacts:Clear:Return:KO": req = this.getRequest(msg.requestID); if (req) - Services.rs.fireError(req, msg.errorMsg); + Services.DOMRequest.fireError(req, msg.errorMsg); break; default: debug("Wrong message: " + aMessage.name); diff --git a/dom/contacts/fallback/ContactDB.jsm b/dom/contacts/fallback/ContactDB.jsm index 4afbcb89da9c..c38afd1192c2 100644 --- a/dom/contacts/fallback/ContactDB.jsm +++ b/dom/contacts/fallback/ContactDB.jsm @@ -377,6 +377,9 @@ ContactDB.prototype = { } } + // Sorting functions takes care of limit if set. + let limit = options.sortBy === 'undefined' ? options.filterLimit : null; + let filter_keys = fields.slice(); for (let key = filter_keys.shift(); key; key = filter_keys.shift()) { let request; @@ -387,13 +390,13 @@ ContactDB.prototype = { debug("Getting index: " + key); // case sensitive let index = store.index(key); - request = index.getAll(options.filterValue, options.filterLimit); + request = index.getAll(options.filterValue, limit); } else { // not case sensitive let tmp = options.filterValue.toLowerCase(); let range = this._global.IDBKeyRange.bound(tmp, tmp + "\uFFFF"); let index = store.index(key + "LowerCase"); - request = index.getAll(range, options.filterLimit); + request = index.getAll(range, limit); } if (!txn.result) txn.result = {}; @@ -410,8 +413,9 @@ ContactDB.prototype = { debug("ContactDB:_findAll: " + JSON.stringify(options)); if (!txn.result) txn.result = {}; - - store.getAll(null, options.filterLimit).onsuccess = function (event) { + // Sorting functions takes care of limit if set. + let limit = options.sortBy === 'undefined' ? options.filterLimit : null; + store.getAll(null, limit).onsuccess = function (event) { debug("Request successful. Record count:", event.target.result.length); for (let i in event.target.result) txn.result[event.target.result[i].id] = this.makeExport(event.target.result[i]); diff --git a/dom/contacts/fallback/ContactService.jsm b/dom/contacts/fallback/ContactService.jsm index 63aa0c9dc006..5eb2b6c6821d 100644 --- a/dom/contacts/fallback/ContactService.jsm +++ b/dom/contacts/fallback/ContactService.jsm @@ -64,6 +64,16 @@ let DOMContactManager = { }, receiveMessage: function(aMessage) { + function sortfunction(a, b){ + let x, y; + if (a.properties[msg.findOptions.sortBy]) + x = a.properties[msg.findOptions.sortBy][0].toLowerCase(); + if (b.properties[msg.findOptions.sortBy]) + y = b.properties[msg.findOptions.sortBy][0].toLowerCase(); + if (msg.findOptions == 'ascending') + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + } debug("Fallback DOMContactManager::receiveMessage " + aMessage.name); let msg = aMessage.json; switch (aMessage.name) { @@ -73,6 +83,13 @@ let DOMContactManager = { function(contacts) { for (let i in contacts) result.push(contacts[i]); + if (msg.findOptions.sortOrder !== 'undefined' && msg.findOptions.sortBy !== 'undefined') { + debug('sortBy: ' + msg.findOptions.sortBy + ', sortOrder: ' + msg.findOptions.sortOrder ); + result.sort(sortfunction); + if (msg.findOptions.filterLimit) + result = result.slice(0, msg.findOptions.filterLimit); + } + debug("result:" + JSON.stringify(result)); ppmm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result}); }.bind(this), diff --git a/dom/contacts/tests/test_contacts_basics.html b/dom/contacts/tests/test_contacts_basics.html index a66c83dbcfad..066c0db099ce 100644 --- a/dom/contacts/tests/test_contacts_basics.html +++ b/dom/contacts/tests/test_contacts_basics.html @@ -28,6 +28,35 @@ Components.classes["@mozilla.org/permissionmanager;1"] "webcontacts-manage", Components.interfaces.nsIPermissionManager.ALLOW_ACTION); +// For Sorting +var c1 = { + name: "a", + familyName: ["a"], + givenName: ["a"], +}; + +var c2 = { + name: "b", + familyName: ["b"], + givenName: ["b"], +}; + +var c3 = { + name: "c", + familyName: ["c","x"], + givenName: ["c","x"], +}; + +var c4 = { + name: "d", + familyName: ["d","e"], + givenName: ["d","e"], +}; + +var c5 = { + name: "empty" +}; + var adr1 = { streetAddress: "street 1", locality: "locality 1", @@ -640,6 +669,18 @@ var steps = [ } req.onerror = onFailure; }, + function () { + ok(true, "Retrieving all contacts with limit 10 and sorted"); + var options = { filterLimit: 10, + sortBy: 'FamilyName', + sortOrder: 'descending' }; + req = mozContacts.find(options); + req.onsuccess = function () { + ok(req.result.length == 10, "10 Entries."); + next(); + } + req.onerror = onFailure; + }, function () { ok(true, "Retrieving all contacts2"); var options = {filterBy: ["name"], @@ -743,6 +784,121 @@ var steps = [ } req.onerror = onFailure; }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(); + createResult1.init(c3); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c3, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(); + createResult1.init(c2); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c2, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(); + createResult1.init(c4); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c4, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(); + createResult1.init(c1); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c1, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "familyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c1); + checkContacts(req.result[1], c2); + checkContacts(req.result[2], c3); + checkContacts(req.result[3], c4); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + var options = {sortBy: "familyName", + sortOrder: "descending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 4, "4 results"); + checkContacts(req.result[0], c4); + checkContacts(req.result[1], c3); + checkContacts(req.result[2], c2); + checkContacts(req.result[3], c1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting"); + createResult1 = new mozContact(); + createResult1.init(c5); + req = navigator.mozContacts.save(createResult1); + req.onsuccess = function () { + ok(createResult1.id, "The contact now has an ID."); + checkContacts(c5, createResult1); + next(); + }; + req.onerror = onFailure; + }, + function () { + ok(true, "Test sorting with empty string"); + var options = {sortBy: "familyName", + sortOrder: "ascending"}; + req = navigator.mozContacts.find(options); + req.onsuccess = function () { + is(req.result.length, 5, "5 results"); + checkContacts(req.result[0], c5); + checkContacts(req.result[1], c1); + checkContacts(req.result[2], c2); + checkContacts(req.result[3], c3); + checkContacts(req.result[4], c4); + 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(); diff --git a/dom/interfaces/contacts/nsIDOMContactProperties.idl b/dom/interfaces/contacts/nsIDOMContactProperties.idl index 7fff1a2a851a..f1ae12812865 100644 --- a/dom/interfaces/contacts/nsIDOMContactProperties.idl +++ b/dom/interfaces/contacts/nsIDOMContactProperties.idl @@ -23,6 +23,8 @@ interface nsIDOMContactFindOptions : nsISupports attribute DOMString filterValue; // e.g. "Tom" attribute DOMString filterOp; // e.g. "contains" attribute jsval filterBy; // DOMString[], e.g. ["givenName", "nickname"] + attribute DOMString sortBy; // e.g. "givenName" + attribute DOMString sortOrder; // e.g. "descending" attribute unsigned long filterLimit; };