Bug 1370475 - Part 2: Convert the address related fields for display purpose. r=lchang

MozReview-Commit-ID: 1Jk0pRc1snu

--HG--
extra : rebase_source : 310824d6952b9f156dcddf6408b376e75623b565
This commit is contained in:
Sean Lee 2017-06-15 17:19:34 +08:00
Родитель e119e20da4
Коммит 7c64597fd1
8 изменённых файлов: 292 добавлений и 11 удалений

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

@ -114,11 +114,14 @@ AutofillProfileAutoCompleteSearch.prototype = {
// Sort addresses by timeLastUsed for showing the lastest used address at top.
addresses.sort((a, b) => b.timeLastUsed - a.timeLastUsed);
let handler = FormAutofillContent.getFormHandler(focusedInput);
let adaptedAddresses = handler.getAdaptedProfiles(addresses);
let allFieldNames = FormAutofillContent.getAllFieldNames(focusedInput);
let result = new ProfileAutoCompleteResult(searchString,
info.fieldName,
allFieldNames,
addresses,
adaptedAddresses,
{});
listener.onSearchResult(this, result);
@ -442,8 +445,8 @@ var FormAutofillContent = {
},
getAllFieldNames(element) {
let formDetails = this.getFormDetails(element);
return formDetails.map(record => record.fieldName);
let formHandler = this.getFormHandler(element);
return formHandler ? formHandler.allFieldNames : null;
},
identifyAutofillFields(element) {

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

@ -90,12 +90,63 @@ FormAutofillHandler.prototype = {
* Set fieldDetails from the form about fields that can be autofilled.
*/
collectFormFields() {
this._cacheValue.allFieldNames = null;
this._formFieldCount = this.form.elements.length;
let fieldDetails = FormAutofillHeuristics.getFormInfo(this.form);
this.fieldDetails = fieldDetails ? fieldDetails : [];
log.debug("Collected details on", this.fieldDetails.length, "fields");
},
getFieldDetailByName(fieldName) {
return this.fieldDetails.find(detail => detail.fieldName == fieldName);
},
_cacheValue: {
allFieldNames: null,
oneLineStreetAddress: null,
},
get allFieldNames() {
if (!this._cacheValue.allFieldNames) {
this._cacheValue.allFieldNames = this.fieldDetails.map(record => record.fieldName);
}
return this._cacheValue.allFieldNames;
},
_getOneLineStreetAddress(address) {
if (!this._cacheValue.oneLineStreetAddress) {
this._cacheValue.oneLineStreetAddress = {};
}
if (!this._cacheValue.oneLineStreetAddress[address]) {
this._cacheValue.oneLineStreetAddress[address] = FormAutofillUtils.toOneLineAddress(address);
}
return this._cacheValue.oneLineStreetAddress[address];
},
_addressTransformer(profile) {
if (profile["street-address"]) {
profile["street-address"] = this._getOneLineStreetAddress(profile["street-address"]);
let waitForConcat = [];
for (let f of ["address-line3", "address-line2", "address-line1"]) {
waitForConcat.unshift(profile[f]);
if (this.getFieldDetailByName(f)) {
if (waitForConcat.length > 1) {
profile[f] = FormAutofillUtils.toOneLineAddress(waitForConcat);
}
waitForConcat = [];
}
}
}
},
getAdaptedProfiles(originalProfiles) {
for (let profile of originalProfiles) {
this._addressTransformer(profile);
}
return originalProfiles;
},
/**
* Processes form fields that can be autofilled, and populates them with the
* profile provided by backend.

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

@ -56,6 +56,24 @@ this.FormAutofillUtils = {
return categories;
},
getAddressSeparator() {
// The separator should be based on the L10N address format, and using a
// white space is a temporary solution.
return " ";
},
toOneLineAddress(address, delimiter = "\n") {
let array = typeof address == "string" ? address.split(delimiter) : address;
if (!Array.isArray(array)) {
return null;
}
return array
.map(s => s.trim())
.filter(s => s)
.join(this.getAddressSeparator());
},
defineLazyLogGetter(scope, logPrefix) {
XPCOMUtils.defineLazyGetter(scope, "log", () => {
let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;

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

@ -152,6 +152,11 @@ ManageProfileDialog.prototype = {
];
let parts = [];
if (address["street-address"]) {
address["street-address"] = FormAutofillUtils.toOneLineAddress(
address["street-address"]
);
}
for (const fieldName of fieldOrder) {
let string = address[fieldName];
if (string) {

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

@ -19,15 +19,17 @@ Form autofill test: simple form address autofill
"use strict";
const {FormAutofillUtils} = SpecialPowers.Cu.import("resource://formautofill/FormAutofillUtils.jsm");
let MOCK_STORAGE = [{
organization: "Sesame Street",
"street-address": "123 Sesame Street.",
"street-address": "123 Sesame Street.\n2-line\n3-line",
tel: "1-345-345-3456",
country: "US",
"address-level1": "NY",
}, {
organization: "Mozilla",
"street-address": "331 E. Evelyn Avenue",
"street-address": "331 E. Evelyn Avenue\n2-line\n3-line",
tel: "1-650-903-0800",
country: "US",
"address-level1": "CA",
@ -67,7 +69,11 @@ function checkFormFilled(address) {
if (document.activeElement == element) {
promises.push(checkAutoCompleteInputFilled(element, address[prop]));
} else {
promises.push(...checkElementFilled(element, address[prop]));
let converted = address[prop];
if (prop == "street-address") {
converted = FormAutofillUtils.toOneLineAddress(converted);
}
promises.push(...checkElementFilled(element, converted));
}
}
doKey("return");
@ -106,21 +112,40 @@ add_task(async function check_menu_when_both_existed() {
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
JSON.stringify({
primary: address.organization,
secondary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
})
));
await setInput("#street-address", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address["street-address"], secondary: address.organization})
JSON.stringify({
primary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
secondary: address.organization,
})
));
await setInput("#tel", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.tel, secondary: address["street-address"]})
JSON.stringify({
primary: address.tel,
secondary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
})
));
await setInput("#address-line1", "");
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({
primary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
secondary: address.organization,
})
));
});
@ -138,7 +163,10 @@ add_task(async function check_fields_after_form_autofill() {
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.organization, secondary: address["street-address"]})
JSON.stringify({
primary: address.organization,
secondary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
})
).slice(1));
doKey("down");
await checkFormFilled(MOCK_STORAGE[1]);
@ -160,7 +188,10 @@ add_task(async function check_form_autofill_resume() {
doKey("down");
await expectPopup();
checkMenuEntries(MOCK_STORAGE.map(address =>
JSON.stringify({primary: address.tel, secondary: address["street-address"]})
JSON.stringify({
primary: address.tel,
secondary: FormAutofillUtils.toOneLineAddress(address["street-address"]),
})
));
});
@ -174,6 +205,7 @@ add_task(async function check_form_autofill_resume() {
<p>This is a basic form.</p>
<p><label>organization: <input id="organization" name="organization" autocomplete="organization" type="text"></label></p>
<p><label>streetAddress: <input id="street-address" name="street-address" autocomplete="street-address" type="text"></label></p>
<p><label>address-line1: <input id="address-line1" name="address-line1" autocomplete="address-line1" type="text"></label></p>
<p><label>tel: <input id="tel" name="tel" autocomplete="tel" type="text"></label></p>
<p><label>email: <input id="email" name="email" autocomplete="email" type="text"></label></p>
<p><label>country: <select id="country" name="country" autocomplete="country">

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

@ -0,0 +1,118 @@
/*
* Test for form auto fill content helper fill all inputs function.
*/
"use strict";
Cu.import("resource://formautofill/FormAutofillHandler.jsm");
const DEFAULT_PROFILE = {
"guid": "123",
"street-address": "2 Harrison St\nline2\nline3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
};
const TESTCASES = [
{
description: "Form with street-address",
document: `<form>
<input id="street-addr" autocomplete="street-address">
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St line2 line3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
}],
},
{
description: "Form with street-address, address-line[1, 2, 3]",
document: `<form>
<input id="street-addr" autocomplete="street-address">
<input id="line1" autocomplete="address-line1">
<input id="line2" autocomplete="address-line2">
<input id="line3" autocomplete="address-line3">
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St line2 line3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2",
"address-line3": "line3",
}],
},
{
description: "Form with street-address, address-line1",
document: `<form>
<input id="street-addr" autocomplete="street-address">
<input id="line1" autocomplete="address-line1">
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St line2 line3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St line2 line3",
"address-line2": "line2",
"address-line3": "line3",
}],
},
{
description: "Form with street-address, address-line[1, 2]",
document: `<form>
<input id="street-addr" autocomplete="street-address">
<input id="line1" autocomplete="address-line1">
<input id="line2" autocomplete="address-line2">
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St line2 line3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St",
"address-line2": "line2 line3",
"address-line3": "line3",
}],
},
{
description: "Form with street-address, address-line[1, 3]",
document: `<form>
<input id="street-addr" autocomplete="street-address">
<input id="line1" autocomplete="address-line1">
<input id="line3" autocomplete="address-line3">
</form>`,
profileData: [Object.assign({}, DEFAULT_PROFILE)],
expectedResult: [{
"guid": "123",
"street-address": "2 Harrison St line2 line3",
"-moz-street-address-one-line": "2 Harrison St line2 line3",
"address-line1": "2 Harrison St line2",
"address-line2": "line2",
"address-line3": "line3",
}],
},
];
for (let testcase of TESTCASES) {
add_task(async function() {
do_print("Starting testcase: " + testcase.description);
let doc = MockDocument.createTestDocument("http://localhost:8080/test/",
testcase.document);
let form = doc.querySelector("form");
let formLike = FormLikeFactory.createFromForm(form);
let handler = new FormAutofillHandler(formLike);
handler.collectFormFields();
let adaptedAddresses = handler.getAdaptedProfiles(testcase.profileData);
Assert.deepEqual(adaptedAddresses, testcase.expectedResult);
});
}

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

@ -0,0 +1,52 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
add_task(async function test_getCategoriesFromFieldNames() {
const TEST_CASES = [
{
strings: ["A", "B", "C", "D"],
expectedValue: "A B C D",
},
{
strings: ["A", "B", "", "D"],
expectedValue: "A B D",
},
{
strings: ["", "B", "", "D"],
expectedValue: "B D",
},
{
strings: "A B C",
expectedValue: "A B C",
},
{
strings: "A\nB\n\n\nC",
expectedValue: "A B C",
},
{
strings: "A B \nC",
expectedValue: "A B C",
},
{
strings: "A-B-C",
expectedValue: "A B C",
delimiter: "-",
},
{
strings: "A B\n \nC",
expectedValue: "A B C",
},
];
for (let tc of TEST_CASES) {
let result;
if (tc.delimiter) {
result = FormAutofillUtils.toOneLineAddress(tc.strings, tc.delimiter);
} else {
result = FormAutofillUtils.toOneLineAddress(tc.strings);
}
Assert.deepEqual(result, tc.expectedValue);
}
});

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

@ -23,6 +23,7 @@ support-files =
[test_creditCardRecords.js]
[test_extractLabelStrings.js]
[test_findLabelElements.js]
[test_getAdaptedProfiles.js]
[test_getCategoriesFromFieldNames.js]
[test_getFormInputDetails.js]
[test_getInfo.js]
@ -33,4 +34,5 @@ support-files =
[test_onFormSubmitted.js]
[test_profileAutocompleteResult.js]
[test_savedFieldNames.js]
[test_toOneLineAddress.js]
[test_transformFields.js]