Bug 1338420 - Part 1: Add initialProcessData autofillSavedFieldNames set and broadcast the changes to content. r?MattN
MozReview-Commit-ID: Dy2xxNQlJig
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -245,30 +245,49 @@ let ProfileAutocomplete = {
* NOTE: Declares it by "var" to make it accessible in unit tests.
*/
var FormAutofillContent = {
/**
* @type {WeakMap} mapping FormLike root HTML elements to FormAutofillHandler objects.
*/
_formsDetails: new WeakMap(),
+ /**
+ * @type {Set} Set of the fields with usable values in any saved profile.
+ */
+ savedFieldNames: null,
+
init() {
FormAutofillUtils.defineLazyLogGetter(this, "FormAutofillContent");
- Services.cpmm.addMessageListener("FormAutofill:enabledStatus", (result) => {
- if (result.data) {
- ProfileAutocomplete.ensureRegistered();
- } else {
- ProfileAutocomplete.ensureUnregistered();
- }
- });
+ Services.cpmm.addMessageListener("FormAutofill:enabledStatus", this);
+ Services.cpmm.addMessageListener("FormAutofill:savedFieldNames", this);
if (Services.cpmm.initialProcessData.autofillEnabled) {
ProfileAutocomplete.ensureRegistered();
}
+
+ this.savedFieldNames =
+ Services.cpmm.initialProcessData.autofillSavedFieldNames || new Set();
+ },
+
+ receiveMessage({name, data}) {
+ switch (name) {
+ case "FormAutofill:enabledStatus": {
+ if (data) {
+ ProfileAutocomplete.ensureRegistered();
+ } else {
+ ProfileAutocomplete.ensureUnregistered();
+ }
+ break;
+ }
+ case "FormAutofill:savedFieldNames": {
+ this.savedFieldNames = data;
+ }
+ }
},
/**
* Get the input's information from cache which is created after page identified.
*
* @param {HTMLInputElement} element Focused input which triggered profile searching
* @returns {Object|null}
* Return target input's information that cloned from content cache
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -80,16 +80,17 @@ FormAutofillParent.prototype = {
// Observing the pref and storage changes
Services.prefs.addObserver(ENABLED_PREF, this, false);
Services.obs.addObserver(this, "formautofill-storage-changed", false);
// Force to trigger the onStatusChanged function for setting listeners properly
// while initizlization
this._setStatus(this._getStatus());
+ this._updateSavedFieldNames();
},
observe(subject, topic, data) {
log.debug("observe:", topic, "with data:", data);
switch (topic) {
case "advanced-pane-loaded": {
let formAutofillPreferences = new FormAutofillPreferences();
let document = subject.document;
@@ -110,16 +111,17 @@ FormAutofillParent.prototype = {
}
case "formautofill-storage-changed": {
// Early exit if the action is not "add" nor "remove"
if (data != "add" && data != "remove") {
break;
}
+ this._updateSavedFieldNames();
let currentStatus = this._getStatus();
if (currentStatus !== this._enabled) {
this._setStatus(currentStatus);
}
break;
}
default: {
@@ -239,9 +241,34 @@ FormAutofillParent.prototype = {
if (info && info.fieldName) {
profiles = this._profileStore.getByFilter({searchString, info});
} else {
profiles = this._profileStore.getAll();
}
target.sendAsyncMessage("FormAutofill:Profiles", profiles);
},
+
+ _updateSavedFieldNames() {
+ if (!Services.ppmm.initialProcessData.autofillSavedFieldNames) {
+ Services.ppmm.initialProcessData.autofillSavedFieldNames = new Set();
+ } else {
+ Services.ppmm.initialProcessData.autofillSavedFieldNames.clear();
+ }
+
+ this._profileStore.getAll().forEach((profile) => {
+ Object.keys(profile).forEach((fieldName) => {
+ if (!profile[fieldName]) {
+ return;
+ }
+ Services.ppmm.initialProcessData.autofillSavedFieldNames.add(fieldName);
+ });
+ });
+
+ // Remove the internal guid and metadata fields.
+ this._profileStore.INTERNAL_FIELDS.forEach((fieldName) => {
+ Services.ppmm.initialProcessData.autofillSavedFieldNames.delete(fieldName);
+ });
+
+ Services.ppmm.broadcastAsyncMessage("FormAutofill:savedFieldNames",
+ Services.ppmm.initialProcessData.autofillSavedFieldNames);
+ },
};
--- a/browser/extensions/formautofill/ProfileStorage.jsm
+++ b/browser/extensions/formautofill/ProfileStorage.jsm
@@ -87,16 +87,19 @@ const MOCK_STORAGE = [{
tel: "1-650-903-0800",
}];
function ProfileStorage(path) {
this._path = path;
}
ProfileStorage.prototype = {
+ // These fields are defined internally for each profile.
+ INTERNAL_FIELDS:
+ ["guid", "timeCreated", "timeLastUsed", "timeLastModified", "timesUsed"],
/**
* Loads the profile data from file to memory.
*
* @returns {Promise}
* @resolves When the operation finished successfully.
* @rejects JavaScript exception.
*/
initialize() {
--- a/browser/extensions/formautofill/test/unit/test_enabledStatus.js
+++ b/browser/extensions/formautofill/test/unit/test_enabledStatus.js
@@ -20,16 +20,17 @@ add_task(function* test_enabledStatus_in
formAutofillParent._uninit();
});
add_task(function* test_enabledStatus_observe() {
let formAutofillParent = new FormAutofillParent();
sinon.stub(formAutofillParent, "_getStatus");
sinon.spy(formAutofillParent, "_setStatus");
+ sinon.stub(formAutofillParent, "_updateSavedFieldNames");
// _enabled = _getStatus() => No need to trigger onStatusChanged
formAutofillParent._enabled = true;
formAutofillParent._getStatus.returns(true);
formAutofillParent.observe(null, "nsPref:changed", "browser.formautofill.enabled");
do_check_eq(formAutofillParent._setStatus.called, false);
// _enabled != _getStatus() => Need to trigger onStatusChanged
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/test_savedFieldNames.js
@@ -0,0 +1,89 @@
+/*
+ * Test for keeping the valid fields information in initialProcessData.
+ */
+
+"use strict";
+
+Cu.import("resource://formautofill/FormAutofillParent.jsm");
+Cu.import("resource://formautofill/ProfileStorage.jsm");
+
+add_task(function* test_profileSavedFieldNames_init() {
+ let formAutofillParent = new FormAutofillParent();
+ sinon.stub(formAutofillParent, "_updateSavedFieldNames");
+
+ formAutofillParent.init();
+ do_check_eq(formAutofillParent._updateSavedFieldNames.called, true);
+
+ formAutofillParent._uninit();
+});
+
+add_task(function* test_profileSavedFieldNames_observe() {
+ let formAutofillParent = new FormAutofillParent();
+ sinon.stub(formAutofillParent, "_updateSavedFieldNames");
+
+ // profile added => Need to trigger updateValidFields
+ formAutofillParent.observe(null, "formautofill-storage-changed", "add");
+ do_check_eq(formAutofillParent._updateSavedFieldNames.called, true);
+
+ // profile removed => Need to trigger updateValidFields
+ formAutofillParent._updateSavedFieldNames.reset();
+ formAutofillParent.observe(null, "formautofill-storage-changed", "remove");
+ do_check_eq(formAutofillParent._updateSavedFieldNames.called, true);
+
+ // profile updated => no need to trigger updateValidFields
+ formAutofillParent._updateSavedFieldNames.reset();
+ formAutofillParent.observe(null, "formautofill-storage-changed", "update");
+ do_check_eq(formAutofillParent._updateSavedFieldNames.called, false);
+});
+
+add_task(function* test_profileSavedFieldNames_update() {
+ let formAutofillParent = new FormAutofillParent();
+ formAutofillParent.init();
+ do_register_cleanup(function cleanup() {
+ Services.prefs.clearUserPref("browser.formautofill.enabled");
+ });
+
+ sinon.stub(formAutofillParent._profileStore, "getAll");
+ formAutofillParent._profileStore.getAll.returns([]);
+
+ // The set is empty if there's no profile in the store.
+ formAutofillParent._updateSavedFieldNames();
+ do_check_eq(Services.ppmm.initialProcessData.autofillSavedFieldNames.size, 0);
+
+ // 2 profiles with 4 valid fields.
+ let fakeStorage = [{
+ guid: "test-guid-1",
+ organization: "Sesame Street",
+ "street-address": "123 Sesame Street.",
+ tel: "1-345-345-3456",
+ email: "",
+ timeCreated: 0,
+ timeLastUsed: 0,
+ timeLastModified: 0,
+ timesUsed: 0,
+ }, {
+ guid: "test-guid-2",
+ organization: "Mozilla",
+ "street-address": "331 E. Evelyn Avenue",
+ tel: "1-650-903-0800",
+ country: "US",
+ timeCreated: 0,
+ timeLastUsed: 0,
+ timeLastModified: 0,
+ timesUsed: 0,
+ }];
+ formAutofillParent._profileStore.getAll.returns(fakeStorage);
+ formAutofillParent._updateSavedFieldNames();
+
+ let autofillSavedFieldNames = Services.ppmm.initialProcessData.autofillSavedFieldNames;
+ do_check_eq(autofillSavedFieldNames.size, 4);
+ do_check_eq(autofillSavedFieldNames.has("organization"), true);
+ do_check_eq(autofillSavedFieldNames.has("street-address"), true);
+ do_check_eq(autofillSavedFieldNames.has("tel"), true);
+ do_check_eq(autofillSavedFieldNames.has("email"), false);
+ do_check_eq(autofillSavedFieldNames.has("guid"), false);
+ do_check_eq(autofillSavedFieldNames.has("timeCreated"), false);
+ do_check_eq(autofillSavedFieldNames.has("timeLastUsed"), false);
+ do_check_eq(autofillSavedFieldNames.has("timeLastModified"), false);
+ do_check_eq(autofillSavedFieldNames.has("timesUsed"), false);
+});
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -5,8 +5,10 @@ support-files =
[test_autofillFormFields.js]
[test_collectFormFields.js]
[test_enabledStatus.js]
[test_getFormInputDetails.js]
[test_markAsAutofillField.js]
[test_profileAutocompleteResult.js]
[test_profileStorage.js]
+[test_savedFieldNames.js]
+