Bug 836519 - Back out 7a145f17e37c for intermittent 'dom/contacts/tests/test_contacts_getall.html | 19 contacts returned - got 20, expected 19' in the test it added. r=intermittent-orange

This commit is contained in:
Jeff Walden 2013-02-16 00:42:26 -08:00
Родитель 42e294f8cb
Коммит 3d6315d338
10 изменённых файлов: 103 добавлений и 801 удалений

Просмотреть файл

@ -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;
let debug;
@ -49,7 +49,7 @@ IndexedDBHelper.prototype = {
if (DEBUG) debug("Try to open database:" + self.dbName + " " + self.dbVersion);
let req = this.dbGlobal.indexedDB.open(this.dbName, this.dbVersion);
req.onsuccess = function (event) {
if (DEBUG) debug("Opened database:" + self.dbName + " " + self.dbVersion);
if (DEBUG) debug("Opened database:" + self.dbName + " " + self.dbName);
self._db = event.target.result;
self._db.onversionchange = function(event) {
if (DEBUG) debug("WARNING: DB modified from a different window.");
@ -60,7 +60,7 @@ IndexedDBHelper.prototype = {
req.onupgradeneeded = function (aEvent) {
if (DEBUG) {
debug("Database needs upgrade:" + self.dbName + aEvent.oldVersion + aEvent.newVersion);
debug("Correct new database version:" + (aEvent.newVersion == this.dbVersion));
debug("Correct new database version:" + aEvent.newVersion == this.dbVersion);
}
let _db = aEvent.target.result;
@ -117,9 +117,7 @@ IndexedDBHelper.prototype = {
txn.oncomplete = function (event) {
if (DEBUG) debug("Transaction complete. Returning to callback.");
if (successCb) {
successCb(txn.result);
}
successCb(txn.result);
};
txn.onabort = function (event) {
@ -128,13 +126,10 @@ IndexedDBHelper.prototype = {
* event.target.error may be null
* if txn was aborted by calling txn.abort()
*/
if (failureCb) {
if (event.target.error) {
if (event.target.error)
failureCb(event.target.error.name);
} else {
else
failureCb("UnknownError");
}
}
};
callback(txn, store);
}.bind(this), failureCb);

Просмотреть файл

@ -134,24 +134,6 @@ ContactTelField.prototype = {
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactTelField])
}
//ContactFindSortOptions
const CONTACTFINDSORTOPTIONS_CONTRACTID = "@mozilla.org/contactFindSortOptions;1"
const CONTACTFINDSORTOPTIONS_CID = Components.ID("{cb008c06-3bf8-495c-8865-f9ca1673a1e1}");
const nsIDOMContactFindSortOptions = Ci.nsIDOMContactFindSortOptions;
function ContactFindSortOptions () { }
ContactFindSortOptions.prototype = {
classID: CONTACTFINDSORTOPTIONS_CID,
classInfo: XPCOMUtils.generateCI({classID: CONTACTFINDSORTOPTIONS_CID,
contractID: CONTACTFINDSORTOPTIONS_CONTRACTID,
classDescription: "ContactFindSortOptions",
interfaces: [nsIDOMContactFindSortOptions],
flags: nsIClassInfo.DOM_OBJECT}),
QueryInterface: XPCOMUtils.generateQI([nsIDOMContactFindSortOptions])
};
//ContactFindOptions
const CONTACTFINDOPTIONS_CONTRACTID = "@mozilla.org/contactFindOptions;1";
@ -166,12 +148,10 @@ ContactFindOptions.prototype = {
classInfo : XPCOMUtils.generateCI({classID: CONTACTFINDOPTIONS_CID,
contractID: CONTACTFINDOPTIONS_CONTRACTID,
classDescription: "ContactFindOptions",
interfaces: [nsIDOMContactFindSortOptions,
nsIDOMContactFindOptions],
interfaces: [nsIDOMContactFindOptions],
flags: nsIClassInfo.DOM_OBJECT}),
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactFindSortOptions,
nsIDOMContactFindOptions])
QueryInterface : XPCOMUtils.generateQI([nsIDOMContactFindOptions])
}
//Contact
@ -212,10 +192,10 @@ Contact.prototype = {
init: function init(aProp) {
// Accept non-array strings for DOMString[] properties and convert them.
function _create(aField) {
function _create(aField) {
if (Array.isArray(aField)) {
for (let i = 0; i < aField.length; i++) {
if (typeof aField[i] != "string")
if (typeof aField[i] !== "string")
aField[i] = String(aField[i]);
}
return aField;
@ -337,7 +317,7 @@ Contact.prototype = {
// ContactManager
const CONTACTMANAGER_CONTRACTID = "@mozilla.org/contactManager;1";
const CONTACTMANAGER_CID = Components.ID("{1d70322b-f11b-4f19-9586-7bf291f212aa}");
const CONTACTMANAGER_CID = Components.ID("{d88af7e0-a45f-11e1-b3dd-0800200c9a66}");
const nsIDOMContactManager = Components.interfaces.nsIDOMContactManager;
function ContactManager()
@ -349,8 +329,6 @@ ContactManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
_oncontactchange: null,
_cursorData: {},
set oncontactchange(aCallback) {
if (DEBUG) debug("set oncontactchange");
let allowCallback = function() {
@ -375,23 +353,19 @@ ContactManager.prototype = {
aNewContact.updated = aRecord.updated;
},
_convertContact: function CM_convertContact(aContact) {
let newContact = new Contact();
newContact.init(aContact.properties);
this._setMetaData(newContact, aContact);
return newContact;
},
_convertContacts: function(aContacts) {
let contacts = [];
_convertContactsArray: function(aContacts) {
let contacts = new Array();
for (let i in aContacts) {
contacts.push(this._convertContact(aContacts[i]));
let newContact = new Contact();
newContact.init(aContacts[i].properties);
this._setMetaData(newContact, aContacts[i]);
contacts.push(newContact);
}
return contacts;
},
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage: " + aMessage.name);
if (DEBUG) debug("Contactmanager::receiveMessage: " + aMessage.name);
let msg = aMessage.json;
let contacts = msg.contacts;
@ -400,21 +374,12 @@ ContactManager.prototype = {
case "Contacts:Find:Return:OK":
req = this.getRequest(msg.requestID);
if (req) {
let result = this._convertContacts(contacts);
let result = this._convertContactsArray(contacts);
Services.DOMRequest.fireSuccess(req.request, result);
} else {
if (DEBUG) debug("no request stored!" + msg.requestID);
}
break;
case "Contacts:GetAll:Next":
let cursor = this._cursorData[msg.cursorId];
let contact = msg.contact ? this._convertContact(msg.contact) : null;
if (contact == null) {
Services.DOMRequest.fireDone(cursor);
} else {
Services.DOMRequest.fireSuccess(cursor, contact);
}
break;
case "Contacts:GetSimContacts:Return:OK":
req = this.getRequest(msg.requestID);
if (req) {
@ -500,7 +465,7 @@ ContactManager.prototype = {
default:
access = "unknown";
}
let requestID = this.getRequestId({
request: aRequest,
allow: function() {
@ -580,7 +545,8 @@ ContactManager.prototype = {
find: function(aOptions) {
if (DEBUG) debug("find! " + JSON.stringify(aOptions));
let request = this.createRequest();
let request;
request = this.createRequest();
let options = { findOptions: aOptions };
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:Find", {requestID: this.getRequestId({request: request, reason: "find"}), options: options});
@ -589,34 +555,6 @@ ContactManager.prototype = {
return request;
},
createCursor: function CM_createCursor(aRequest) {
let id = this._getRandomId();
let cursor = Services.DOMRequest.createCursor(this._window, function() {
this.handleContinue(id);
}.bind(this));
if (DEBUG) debug("saved cursor id: " + id);
this._cursorData[id] = cursor;
return [id, cursor];
},
getAll: function CM_getAll(aOptions) {
if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));
let [cursorId, cursor] = this.createCursor();
let allowCallback = function() {
cpmm.sendAsyncMessage("Contacts:GetAll", {
cursorId: cursorId, findOptions: aOptions});
}.bind(this);
this.askPermission("find", cursor, allowCallback);
return cursor;
},
handleContinue: function CM_handleContinue(aCursorId) {
if (DEBUG) debug("handleContinue: " + aCursorId);
cpmm.sendAsyncMessage("Contacts:GetAll:Continue", {
cursorId: aCursorId
});
},
remove: function removeContact(aRecord) {
let request;
request = this.createRequest();
@ -671,8 +609,7 @@ ContactManager.prototype = {
"Contacts:GetSimContacts:Return:OK",
"Contacts:GetSimContacts:Return:KO",
"Contact:Changed",
"PermissionPromptHelper:AskPermission:OK",
"Contacts:GetAll:Next"]);
"PermissionPromptHelper:AskPermission:OK"]);
},
// Called from DOMRequestIpcHelper
@ -693,4 +630,4 @@ ContactManager.prototype = {
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
[Contact, ContactManager, ContactProperties, ContactAddress, ContactField, ContactTelField, ContactFindSortOptions, ContactFindOptions])
[Contact, ContactManager, ContactProperties, ContactAddress, ContactField, ContactTelField, ContactFindOptions])

Просмотреть файл

@ -10,16 +10,13 @@ contract @mozilla.org/contactField;1 {e2cb19c0-e4aa-11e1-9b23-0800200c9a66}
component {ed0ab260-e4aa-11e1-9b23-0800200c9a66} ContactManager.js
contract @mozilla.org/contactTelField;1 {ed0ab260-e4aa-11e1-9b23-0800200c9a66}
component {cb008c06-3bf8-495c-8865-f9ca1673a1e1} ContactManager.js
contract @mozilla.org/contactFindSortOptions;1 {cb008c06-3bf8-495c-8865-f9ca1673a1e1}
component {e13ca4c5-c9cd-40bb-95e9-b636d42f5edf} ContactManager.js
contract @mozilla.org/contactFindOptions;1 {e13ca4c5-c9cd-40bb-95e9-b636d42f5edf}
component {e31daea0-0cb6-11e1-be50-0800200c9a66} ContactManager.js
contract @mozilla.org/contactFindOptions;1 {e31daea0-0cb6-11e1-be50-0800200c9a66}
component {da0f7040-388b-11e1-b86c-0800200c9a66} ContactManager.js
contract @mozilla.org/contact;1 {da0f7040-388b-11e1-b86c-0800200c9a66}
category JavaScript-global-constructor mozContact @mozilla.org/contact;1
component {1d70322b-f11b-4f19-9586-7bf291f212aa} ContactManager.js
contract @mozilla.org/contactManager;1 {1d70322b-f11b-4f19-9586-7bf291f212aa}
component {d88af7e0-a45f-11e1-b3dd-0800200c9a66} ContactManager.js
contract @mozilla.org/contactManager;1 {d88af7e0-a45f-11e1-b3dd-0800200c9a66}
category JavaScript-navigator-property mozContacts @mozilla.org/contactManager;1

Просмотреть файл

@ -18,9 +18,8 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
const DB_NAME = "contacts";
const DB_VERSION = 8;
const DB_VERSION = 7;
const STORE_NAME = "contacts";
const SAVED_GETALL_STORE_NAME = "getallcache";
this.ContactDB = function ContactDB(aGlobal) {
if (DEBUG) debug("Constructor");
@ -30,8 +29,6 @@ this.ContactDB = function ContactDB(aGlobal) {
ContactDB.prototype = {
__proto__: IndexedDBHelper.prototype,
cursorData: {},
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
@ -241,9 +238,6 @@ ContactDB.prototype = {
objectStore.deleteIndex(names[i]);
}
}
} else if (currVersion == 7) {
if (DEBUG) debug("Adding object store for cached searches");
db.createObjectStore(SAVED_GETALL_STORE_NAME);
}
}
},
@ -388,41 +382,6 @@ ContactDB.prototype = {
record.updated = new Date();
},
removeObjectFromCache: function CDB_removeObjectFromCache(aObjectId, aCallback) {
if (DEBUG) debug("removeObjectFromCache: " + aObjectId);
if (!aObjectId) {
if (DEBUG) debug("No object ID passed");
return;
}
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function(txn, store) {
store.openCursor().onsuccess = function(e) {
let cursor = e.target.result;
if (cursor) {
for (let i = 0; i < cursor.value.length; ++i) {
if (cursor.value[i] == aObjectId) {
if (DEBUG) debug("id matches cache");
cursor.value.splice(i, 1);
cursor.update(cursor.value);
break;
}
}
cursor.continue();
} else {
aCallback();
}
}.bind(this);
}.bind(this));
},
// Invalidate the entire cache. It will be incrementally regenerated on demand
// See getCacheForQuery
invalidateCache: function CDB_invalidateCache() {
if (DEBUG) debug("invalidate cache");
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function (txn, store) {
store.clear();
});
},
saveContact: function saveContact(aContact, successCb, errorCb) {
let contact = this.makeImport(aContact);
this.newTxn("readwrite", STORE_NAME, function (txn, store) {
@ -449,20 +408,15 @@ ContactDB.prototype = {
store.put(contact);
}
}
this.invalidateCache();
}.bind(this);
}.bind(this), successCb, errorCb);
},
removeContact: function removeContact(aId, aSuccessCb, aErrorCb) {
if (DEBUG) debug("removeContact: " + aId);
this.removeObjectFromCache(aId, function() {
this.newTxn("readwrite", STORE_NAME, function(txn, store) {
store.delete(aId).onsuccess = function() {
aSuccessCb();
}
}, null, aErrorCb);
}.bind(this));
this.newTxn("readwrite", STORE_NAME, function (txn, store) {
if (DEBUG) debug("Going to delete" + aId);
store.delete(aId);
}, aSuccessCb, aErrorCb);
},
clear: function clear(aSuccessCb, aErrorCb) {
@ -472,164 +426,6 @@ ContactDB.prototype = {
}, aSuccessCb, aErrorCb);
},
getObjectById: function CDB_getObjectById(aStore, aObjectId, aCallback) {
if (DEBUG) debug("getObjectById: " + aStore + ":" + aObjectId);
this.newTxn("readonly", aStore, function (txn, store) {
let req = store.get(aObjectId);
req.onsuccess = function (event) {
aCallback(event.target.result);
};
req.onerror = function (event) {
aCallback(null);
};
});
},
getCacheForQuery: function CDB_getCacheForQuery(aQuery, aCursorId, aSuccessCb) {
if (DEBUG) debug("getCacheForQuery");
// Here we try to get the cached results for query `aQuery'. If they don't
// exist, it means the cache was invalidated and needs to be recreated, so
// we do that. Otherwise, we just return the existing query.
this.getObjectById(SAVED_GETALL_STORE_NAME, aQuery, function (aCache) {
if (!aCache) {
if (DEBUG) debug("creating cache for query " + aQuery);
this.createCacheForQuery(aQuery, aCursorId, aSuccessCb);
} else {
if (DEBUG) debug("cache exists");
if (!this.cursorData[aCursorId]) {
this.cursorData[aCursorId] = aCache;
}
aSuccessCb(aCache);
}
}.bind(this));
},
setCacheForQuery: function CDB_setCacheForQuery(aQuery, aCache, aCallback) {
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function (txn, store) {
let req = store.put(aCache, aQuery);
if (!aCallback) {
return;
}
req.onsuccess = function () {
aCallback(true);
};
req.onerror = function () {
aCallback(false);
};
});
},
createCacheForQuery: function CDB_createCacheForQuery(aQuery, aCursorId, aSuccessCb, aFailureCb) {
this.find(function (aContacts) {
if (aContacts) {
let contactsArray = [];
for (let i in aContacts) {
contactsArray.push(aContacts[i].id);
}
this.setCacheForQuery(aQuery, contactsArray);
this.cursorData[aCursorId] = contactsArray;
aSuccessCb(contactsArray);
} else {
aSuccessCb(null);
}
}.bind(this),
function (aErrorMsg) { aFailureCb(aErrorMsg); },
JSON.parse(aQuery));
},
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
// Recreate the cache for this query if needed
let optionStr = JSON.stringify(aOptions);
this.getCacheForQuery(optionStr, aCursorId, function (aCachedResults) {
if (aCachedResults && aCachedResults.length > 0) {
if (DEBUG) debug("query returned at least one contact");
this.getObjectById(STORE_NAME, aCachedResults[0], function (aContact) {
this.cursorData[aCursorId].shift();
aSuccessCb(aContact);
}.bind(this));
} else { // no contacts
if (DEBUG) debug("query returned no contacts");
aSuccessCb(null);
}
}.bind(this));
},
getNext: function CDB_getNext(aSuccessCb, aFailureCb, aCursorId) {
if (DEBUG) debug("ContactDB:getNext: " + aCursorId);
let aCachedResults = this.cursorData[aCursorId];
if (DEBUG) debug("got transient cache");
if (aCachedResults.length > 0) {
this.getObjectById(STORE_NAME, aCachedResults[0], function(aContact) {
this.cursorData[aCursorId].shift();
if (aContact) {
aSuccessCb(aContact);
} else {
// If the contact ID in cache is invalid, it was removed recently and
// the cache hasn't been updated to reflect the change, so we skip it.
if (DEBUG) debug("invalid contact in cache: " + aCachedResults[0]);
return this.getNext(aSuccessCb, aFailureCb, aCursorId);
}
}.bind(this));
} else { // last contact
delete this.cursorData[aCursorId];
aSuccessCb(null);
}
},
releaseCursors: function CDB_releaseCursors(aCursors) {
for (let i of aCursors) {
delete this.cursorData[i];
}
},
/*
* 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
* sorting with the other sortyBy field.
*/
sortResults: function CDB_sortResults(aResults, aFindOptions) {
if (!aFindOptions)
return;
if (aFindOptions.sortBy != "undefined") {
aResults.sort(function (a, b) {
let x, y;
let result = 0;
let sortOrder = aFindOptions.sortOrder;
let sortBy = aFindOptions.sortBy == "familyName" ? [ "familyName", "givenName" ] : [ "givenName" , "familyName" ];
let xIndex = 0;
let yIndex = 0;
do {
while (xIndex < sortBy.length && !x) {
x = a.properties[sortBy[xIndex]] ? a.properties[sortBy[xIndex]][0].toLowerCase() : null;
xIndex++;
}
if (!x) {
return sortOrder == 'ascending' ? 1 : -1;
}
while (yIndex < sortBy.length && !y) {
y = b.properties[sortBy[yIndex]] ? b.properties[sortBy[yIndex]][0].toLowerCase() : null;
yIndex++;
}
if (!y) {
return sortOrder == 'ascending' ? 1 : -1;
}
result = x.localeCompare(y);
x = null;
y = null;
} while (result == 0);
return sortOrder == 'ascending' ? result : -result;
});
}
if (aFindOptions.filterLimit && aFindOptions.filterLimit != 0) {
if (DEBUG) debug("filterLimit is set: " + aFindOptions.filterLimit);
aResults.splice(aFindOptions.filterLimit, aResults.length);
}
},
/**
* @param successCb
* Callback function to invoke with result array.
@ -643,7 +439,7 @@ ContactDB.prototype = {
* - count
*/
find: function find(aSuccessCb, aFailureCb, aOptions) {
if (DEBUG) debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp);
if (DEBUG) debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp + "\n");
let self = this;
this.newTxn("readonly", STORE_NAME, function (txn, store) {
if (aOptions && (aOptions.filterOp == "equals" || aOptions.filterOp == "contains")) {
@ -659,7 +455,7 @@ ContactDB.prototype = {
let fields = options.filterBy;
for (let key in fields) {
if (DEBUG) debug("key: " + fields[key]);
if (!store.indexNames.contains(fields[key]) && fields[key] != "id") {
if (!store.indexNames.contains(fields[key]) && !fields[key] == "id") {
if (DEBUG) debug("Key not valid!" + fields[key] + ", " + store.indexNames);
txn.abort();
return;
@ -710,8 +506,7 @@ ContactDB.prototype = {
txn.result = {};
request.onsuccess = function (event) {
if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
this.sortResults(event.target.result, options);
if (DEBUG) 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]);
}.bind(this);
@ -725,15 +520,13 @@ ContactDB.prototype = {
// Sorting functions takes care of limit if set.
let limit = options.sortBy === 'undefined' ? options.filterLimit : null;
store.mozGetAll(null, limit).onsuccess = function (event) {
if (DEBUG) debug("Request successful. Record count:" + event.target.result.length);
this.sortResults(event.target.result, options);
for (let i in event.target.result) {
if (DEBUG) 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]);
}
}.bind(this);
},
init: function init(aGlobal) {
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME, SAVED_GETALL_STORE_NAME], aGlobal);
this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME], aGlobal);
}
};

Просмотреть файл

@ -7,7 +7,7 @@
const DEBUG = false;
function debug(s) { dump("-*- Fallback ContactService component: " + s + "\n"); }
const Cu = Components.utils;
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -37,18 +37,15 @@ XPCOMUtils.defineLazyGetter(this, "mRIL", function () {
let myGlobal = this;
this.DOMContactManager = {
// maps children to their live cursors so we can cleanup on shutdown/crash
_liveCursors: {},
init: function() {
if (DEBUG) debug("Init");
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:Continue", "Contacts:Clear", "Contact:Save",
this._messages = ["Contacts:Find", "Contacts:Clear", "Contact:Save",
"Contact:Remove", "Contacts:GetSimContacts",
"Contacts:RegisterForMessages", "child-process-shutdown"];
this._children = [];
this._messages.forEach(function(msgName) {
this._messages.forEach((function(msgName) {
ppmm.addMessageListener(msgName, this);
}.bind(this));
}).bind(this));
var idbManager = Components.classes["@mozilla.org/dom/indexeddb/manager;1"].getService(Ci.nsIIndexedDatabaseManager);
idbManager.initWindowless(myGlobal);
@ -60,9 +57,9 @@ this.DOMContactManager = {
observe: function(aSubject, aTopic, aData) {
myGlobal = null;
this._messages.forEach(function(msgName) {
this._messages.forEach((function(msgName) {
ppmm.removeMessageListener(msgName, this);
}.bind(this));
}).bind(this));
Services.obs.removeObserver(this, "profile-before-change");
ppmm = null;
this._messages = null;
@ -73,7 +70,7 @@ this.DOMContactManager = {
assertPermission: function(aMessage, aPerm) {
if (!aMessage.target.assertPermission(aPerm)) {
Cu.reportError("Contacts message " + aMessage.name +
Cu.reportError("Contacts message " + msg.name +
" from a content process with no" + aPerm + " privileges.");
return false;
}
@ -87,56 +84,74 @@ this.DOMContactManager = {
},
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage " + aMessage.name);
if (DEBUG) debug("Fallback DOMContactManager::receiveMessage " + aMessage.name);
let mm = aMessage.target;
let msg = aMessage.data;
/*
* Sorting the contacts by sortBy field. sortBy can either be familyName or givenName.
* If 2 entries have the same sortyBy field or no sortBy field is present, we continue
* sorting with the other sortyBy field.
*/
function sortfunction(a, b){
let x, y;
let result = 0;
let findOptions = msg.options.findOptions;
let sortOrder = findOptions.sortOrder;
let sortBy = findOptions.sortBy === "familyName" ? [ "familyName", "givenName" ] : [ "givenName" , "familyName" ];
let xIndex = 0;
let yIndex = 0;
do {
while (xIndex < sortBy.length && !x) {
x = a.properties[sortBy[xIndex]] ? a.properties[sortBy[xIndex]][0].toLowerCase() : null;
xIndex++;
}
if (!x) {
return sortOrder == 'ascending' ? 1 : -1;
}
while (yIndex < sortBy.length && !y) {
y = b.properties[sortBy[yIndex]] ? b.properties[sortBy[yIndex]][0].toLowerCase() : null;
yIndex++;
}
if (!y) {
return sortOrder == 'ascending' ? 1 : -1;
}
result = x.localeCompare(y);
x = null;
y = null;
} while (result === 0);
return sortOrder == 'ascending' ? result : -result;
}
switch (aMessage.name) {
case "Contacts:Find":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
let result = [];
let result = new Array();
this._db.find(
function(contacts) {
for (let i in contacts) {
for (let i in contacts)
result.push(contacts[i]);
if (msg.options && msg.options.findOptions) {
let findOptions = msg.options.findOptions;
if (findOptions.sortOrder !== 'undefined' && findOptions.sortBy !== 'undefined') {
if (DEBUG) debug('sortBy: ' + findOptions.sortBy + ', sortOrder: ' + findOptions.sortOrder );
result.sort(sortfunction);
if (findOptions.filterLimit)
result = result.slice(0, findOptions.filterLimit);
}
}
if (DEBUG) debug("result:" + JSON.stringify(result));
mm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }) }.bind(this),
msg.options.findOptions);
break;
case "Contacts:GetAll":
if (!this.assertPermission(aMessage, "contacts-read")) {
return null;
}
this._db.getAll(
function(aContact) {
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contact: aContact});
},
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
msg.findOptions, msg.cursorId);
if (Array.isArray(this._liveCursors[mm])) {
this._liveCursors[mm].push(msg.cursorId);
} else {
this._liveCursors[mm] = [msg.cursorId];
}
break;
case "Contacts:GetAll:Continue":
this._db.getNext(
function(aContact) {
if (aContact == null) { // last contact, release the cursor
let cursors = this._liveCursors[mm];
cursors.splice(cursors.indexOf(msg.cursorId), 1);
}
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contact: aContact});
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
msg.cursorId);
break;
case "Contact:Save":
if (msg.options.reason === "create") {
if (!this.assertPermission(aMessage, "contacts-create")) {
@ -210,8 +225,6 @@ this.DOMContactManager = {
break;
case "child-process-shutdown":
if (DEBUG) debug("Unregister");
this._db.releaseCursors(this._liveCursors[mm]);
delete this._liveCursors[mm];
let index = this._children.indexOf(mm);
if (index != -1) {
if (DEBUG) debug("Unregister index: " + index);

Просмотреть файл

@ -19,7 +19,6 @@ MOCHITEST_FILES = \
test_contacts_events.html \
test_contacts_blobs.html \
test_contacts_international.html \
test_contacts_getall.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -1,422 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=836519
-->
<head>
<title>Mozilla Bug 836519</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=836519">Mozilla Bug 836519</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript;version=1.8">
"use strict";
// this shouldn't be necessary when bug 792594 is fixed
if (!SpecialPowers.getBoolPref("dom.mozContacts.enabled")) {
let comp = SpecialPowers.wrap(SpecialPowers.Components);
comp.utils.import("resource://gre/modules/ContactService.jsm");
comp.utils.import("resource://gre/modules/PermissionPromptHelper.jsm");
SpecialPowers.setBoolPref("dom.mozContacts.enabled", true);
}
SpecialPowers.addPermission("contacts-write", true, document);
SpecialPowers.addPermission("contacts-read", true, document);
SpecialPowers.addPermission("contacts-create", true, document);
let adr1 = {
type: "work",
streetAddress: "street 1",
locality: "locality 1",
region: "region 1",
postalCode: "postal code 1",
countryName: "country 1"
};
let properties1 = {
name: "Testname1",
familyName: ["TestFamilyName","Wagner"],
givenName: ["Test1","Test2"],
nickname: "nicktest",
tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+9-876-5432"}],
adr: adr1,
email: [{type: ["work"], value: "x@y.com"}]
};
function onUnwantedSuccess() {
ok(false, "onUnwantedSuccess: shouldn't get here");
}
function onFailure() {
ok(false, "in on Failure!");
}
function checkStr(str1, str2, msg) {
if (str1)
ok(typeof str1 == "string" ? [str1] : str1, (typeof str2 == "string") ? [str2] : str2, msg);
}
function checkAddress(adr1, adr2) {
checkStr(adr1.type, adr2.type, "Same type");
checkStr(adr1.streetAddress, adr2.streetAddress, "Same streetAddress");
checkStr(adr1.locality, adr2.locality, "Same locality");
checkStr(adr1.region, adr2.region, "Same region");
checkStr(adr1.postalCode, adr2.postalCode, "Same postalCode");
checkStr(adr1.countryName, adr2.countryName, "Same countryName");
}
function checkTel(tel1, tel2) {
checkStr(tel1.type, tel2.type, "Same type");
checkStr(tel1.value, tel2.value, "Same value");
checkStr(tel1.carrier, tel2.carrier, "Same carrier");
}
function checkField(field1, field2) {
checkStr(field1.type, field2.type, "Same type");
checkStr(field1.value, field2.value, "Same value");
}
function checkContacts(contact1, contact2) {
checkStr(contact1.name, contact2.name, "Same name");
checkStr(contact1.honorificPrefix, contact2.honorificPrefix, "Same honorificPrefix");
checkStr(contact1.givenName, contact2.givenName, "Same givenName");
checkStr(contact1.additionalName, contact2.additionalName, "Same additionalName");
checkStr(contact1.familyName, contact2.familyName, "Same familyName");
checkStr(contact1.honorificSuffix, contact2.honorificSuffix, "Same honorificSuffix");
checkStr(contact1.nickname, contact2.nickname, "Same nickname");
checkStr(contact1.category, contact2.category, "Same category");
checkStr(contact1.org, contact2.org, "Same org");
checkStr(contact1.jobTitle, contact2.jobTitle, "Same jobTitle");
is(contact1.bday ? contact1.bday.valueOf() : null, contact2.bday ? contact2.bday.valueOf() : null, "Same birthday");
checkStr(contact1.note, contact2.note, "Same note");
is(contact1.anniversary ? contact1.anniversary.valueOf() : null , contact2.anniversary ? contact2.anniversary.valueOf() : null, "Same anniversary");
is(contact1.sex, contact2.sex, "Same sex");
is(contact1.genderIdentity, contact2.genderIdentity, "Same genderIdentity");
for (let i in contact1.email) {
if (contact1.email) {
ok(contact2.email != null, "conatct2.email exists");
}
if (contact2.email) {
ok(contact1.email != null, "conatct1.email exists");
}
checkField(contact1.email[i], contact2.email[i]);
}
for (let i in contact1.adr) {
if (contact1.adr) {
ok(contact2.adr != null, "conatct2.adr exists");
}
if (contact2.adr) {
ok(contact1.adr != null, "conatct1.adr exists");
}
checkAddress(contact1.adr[i], contact2.adr[i]);
}
for (let i in contact1.tel) {
if (contact1.tel) {
ok(contact2.tel != null, "conatct2.tel exists");
}
if (contact2.tel) {
ok(contact1.tel != null, "conatct1.tel exists");
}
checkTel(contact1.tel[i], contact2.tel[i]);
}
for (let i in contact1.url) {
if (contact1.url) {
ok(contact2.url != null, "conatct2.url exists");
}
if (contact2.url) {
ok(contact1.url != null, "conatct1.url exists");
}
checkField(contact1.url[i], contact2.url[i]);
}
for (let i in contact1.impp) {
if (contact1.impp) {
ok(contact2.impp != null, "conatct2.impp exists");
}
if (contact2.impp) {
ok(contact1.impp != null, "conatct1.impp exists");
}
checkField(contact1.impp[i], contact2.impp[i]);
}
}
function clearDatabase() {
ok(true, "Clearing database");
req = mozContacts.clear();
req.onsuccess = function() {
ok(true, "Cleared the database");
next();
};
req.onerror = onFailure;
}
function add20Contacts() {
ok(true, "Adding 20 contacts");
for (let i=0; i<19; i++) {
createResult1 = new mozContact();
createResult1.init(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
ok(createResult1.id, "The contact now has an ID.");
};
req.onerror = onFailure;
};
createResult1 = new mozContact();
createResult1.init(properties1);
req = mozContacts.save(createResult1);
req.onsuccess = function() {
ok(createResult1.id, "The contact now has an ID.");
ok(createResult1.name == properties1.name, "Same Name");
next();
};
req.onerror = onFailure;
}
let createResult1;
let index = 0;
let req;
let mozContacts = window.navigator.mozContacts;
let steps = [
clearDatabase,
function() {
// add a contact
createResult1 = new mozContact();
createResult1.init({});
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function() {
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Retrieving one contact with getAll");
req = mozContacts.getAll({});
let count = 0;
req.onsuccess = function(event) {
ok(true, "on success");
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 1, "last contact - only one contact returned");
next();
}
};
req.onerror = onFailure;
},
clearDatabase,
add20Contacts,
function() {
ok(true, "Retrieving 20 contacts with getAll");
req = mozContacts.getAll({});
let count = 0;
req.onsuccess = function(event) {
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 20, "last contact - 20 contacts returned");
next();
}
};
req.onerror = onFailure;
},
function() {
ok(true, "Deleting one contact");
req = mozContacts.remove(createResult1);
req.onsuccess = function() {
next();
};
req.onerror = onFailure;
},
function() {
ok(true, "Test cache invalidation");
req = mozContacts.getAll({});
let count = 0;
req.onsuccess = function(event) {
ok(true, "on success");
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 19, "last contact - 19 contacts returned");
next();
}
};
req.onerror = onFailure;
},
clearDatabase,
add20Contacts,
function() {
ok(true, "Test cache invalidation between getAll and getNext");
req = mozContacts.getAll({});
let count = 0;
let firstResult = true;
req.onsuccess = function(event) {
ok(true, "on success");
if (firstResult) {
if (req.result) {
count++;
}
let delReq = mozContacts.remove(createResult1);
delReq.onsuccess = function() {
firstResult = false;
req.continue();
};
} else {
if (req.result) {
ok(true, "result is valid");
count++;
req.continue();
} else {
is(count, 19, "19 contacts returned");
ok(true, "last contact");
next();
}
}
};
},
clearDatabase,
add20Contacts,
function() {
ok(true, "Delete the currect contact while iterating");
req = mozContacts.getAll({});
let count = 0;
let previousId = null;
req.onsuccess = function() {
if (req.result) {
ok(true, "on success");
if (previousId) {
isnot(previousId, req.result.id, "different contacts returned");
}
previousId = req.result.id;
count++;
let delReq = mozContacts.remove(req.result);
delReq.onsuccess = function() {
ok(true, "deleted current contact");
req.continue();
};
} else {
is(count, 20, "returned 20 contacts");
next();
}
};
},
clearDatabase,
add20Contacts,
function() {
ok(true, "Iterating through the contact list inside a cursor callback");
let count1 = 0, count2 = 0;
let req1 = mozContacts.getAll({});
let req2;
req1.onsuccess = function() {
if (count1 == 0) {
count1++;
req2 = mozContacts.getAll({});
req2.onsuccess = function() {
if (req2.result) {
count2++;
req2.continue();
} else {
is(count2, 20, "inner cursor returned 20 contacts");
req1.continue();
}
};
} else {
if (req1.result) {
count1++;
req1.continue();
} else {
is(count1, 20, "outer cursor returned 20 contacts");
next();
}
}
};
},
clearDatabase,
add20Contacts,
function() {
ok(true, "20 concurrent cursors");
const NUM_CURSORS = 20;
let completed = 0;
let createCursor = function(aNum) {
let count = 0;
let req = mozContacts.getAll({});
req.onsuccess = function() {
if (req.result) {
count++;
req.continue();
} else {
is(count, 20, "cursor " + aNum + " returned 20 contacts");
if (++completed == NUM_CURSORS) {
next();
}
}
}.bind(this);
}.bind(this);
for (let i = 0; i < NUM_CURSORS; ++i) {
createCursor(i);
}
},
clearDatabase,
function() {
ok(true, "all done!\n");
SimpleTest.finish();
}
];
function next() {
ok(true, "Begin!");
if (index >= steps.length) {
ok(false, "Shouldn't get here!");
return;
}
try {
steps[index++]();
} catch(ex) {
ok(false, "Caught exception", ex);
}
}
function permissionTest() {
if (gContactsEnabled) {
next();
} else {
is(mozContacts, null, "mozContacts is null when not enabled.");
SimpleTest.finish();
}
}
let gContactsEnabled = SpecialPowers.getBoolPref("dom.mozContacts.enabled");
SimpleTest.waitForExplicitFinish();
addLoadEvent(permissionTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -7,11 +7,9 @@
#include "nsIDOMEventTarget.idl"
interface nsIArray;
interface nsIDOMContactFindSortOptions;
interface nsIDOMContactFindOptions;
interface nsIDOMContactProperties;
interface nsIDOMDOMRequest;
interface nsIDOMDOMCursor;
[scriptable, uuid(da0f7040-388b-11e1-b86c-0800200c9a66)]
interface nsIDOMContact : nsIDOMContactProperties
@ -23,17 +21,15 @@ interface nsIDOMContact : nsIDOMContactProperties
void init(in nsIDOMContactProperties properties); // Workaround BUG 723206
};
[scriptable, uuid(1d70322b-f11b-4f19-9586-7bf291f212aa)]
[scriptable, uuid(d88af7e0-a45f-11e1-b3dd-0800200c9a66)]
interface nsIDOMContactManager : nsISupports
{
nsIDOMDOMRequest find(in nsIDOMContactFindOptions options);
nsIDOMDOMCursor getAll(in nsIDOMContactFindSortOptions options);
nsIDOMDOMRequest clear();
nsIDOMDOMRequest save(in nsIDOMContact contact);
nsIDOMDOMRequest remove(in nsIDOMContact contact);
nsIDOMDOMRequest getSimContacts(in DOMString type);

Просмотреть файл

@ -31,19 +31,14 @@ interface nsIDOMContactTelField : nsIDOMContactField
attribute DOMString carrier;
};
[scriptable, uuid(cb008c06-3bf8-495c-8865-f9ca1673a1e1)]
interface nsIDOMContactFindSortOptions : nsISupports
{
attribute DOMString sortBy; // "givenName" or "familyName"
attribute DOMString sortOrder; // e.g. "descending"
};
[scriptable, uuid(e13ca4c5-c9cd-40bb-95e9-b636d42f5edf)]
interface nsIDOMContactFindOptions : nsIDOMContactFindSortOptions
[scriptable, uuid(e31daea0-0cb6-11e1-be50-0800200c9a66)]
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; // "givenName" or "familyName"
attribute DOMString sortOrder; // e.g. "descending"
attribute unsigned long filterLimit;
};

Просмотреть файл

@ -406,7 +406,6 @@ var interfaceNamesInGlobalScope =
"XULMenuListElement",
"SVGTransform",
"SVGTextPositioningElement",
"ContactFindSortOptions",
"ContactFindOptions",
"SVGFEMergeElement",
"FileRequest",