mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1020607 - Populate pending elements with values given by requestAutocomplete UI. r=MattN
This commit is contained in:
parent
100c420152
commit
27209f0b98
@ -27,6 +27,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
function FormHandler(aForm, aWindow) {
|
||||
this.form = aForm;
|
||||
this.window = aWindow;
|
||||
|
||||
this.fieldDetails = [];
|
||||
}
|
||||
|
||||
FormHandler.prototype = {
|
||||
@ -40,6 +42,21 @@ FormHandler.prototype = {
|
||||
*/
|
||||
window: null,
|
||||
|
||||
/**
|
||||
* Array of collected data about relevant form fields. Each item is an object
|
||||
* storing the identifying details of the field and a reference to the
|
||||
* originally associated element from the form.
|
||||
*
|
||||
* The "section", "addressType", "contactType", and "fieldName" values are
|
||||
* used to identify the exact field when the serializable data is received
|
||||
* from the requestAutocomplete user interface. There cannot be multiple
|
||||
* fields which have the same exact combination of these values.
|
||||
*
|
||||
* A direct reference to the associated element cannot be sent to the user
|
||||
* interface because processing may be done in the parent process.
|
||||
*/
|
||||
fieldDetails: null,
|
||||
|
||||
/**
|
||||
* Handles requestAutocomplete and generates the DOM events when finished.
|
||||
*/
|
||||
@ -49,14 +66,7 @@ FormHandler.prototype = {
|
||||
// string indicates that an unexpected exception occurred.
|
||||
let reason = "";
|
||||
try {
|
||||
let data = this.collectFormElements();
|
||||
|
||||
let ui = yield FormAutofill.integration.createRequestAutocompleteUI(data);
|
||||
let result = yield ui.show();
|
||||
|
||||
// At present, we only have cancellation and success cases, since we
|
||||
// don't do any validation or precondition check.
|
||||
reason = result.canceled ? "cancel" : "success";
|
||||
reason = yield this.promiseRequestAutocomplete();
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
@ -72,10 +82,39 @@ FormHandler.prototype = {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Collects information from the form about fields that can be autofilled, and
|
||||
* returns an object that can be used to build RequestAutocompleteUI.
|
||||
* Handles requestAutocomplete and returns the outcome when finished.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The "reason" value indicating the outcome of the
|
||||
* requestAutocomplete operation, including "success" if the
|
||||
* operation completed successfully.
|
||||
*/
|
||||
collectFormElements: function () {
|
||||
promiseRequestAutocomplete: Task.async(function* () {
|
||||
let data = this.collectFormFields();
|
||||
if (!data) {
|
||||
return "disabled";
|
||||
}
|
||||
|
||||
let ui = yield FormAutofill.integration.createRequestAutocompleteUI(data);
|
||||
let result = yield ui.show();
|
||||
if (result.canceled) {
|
||||
return "cancel";
|
||||
}
|
||||
|
||||
this.autofillFormFields(result);
|
||||
|
||||
return "success";
|
||||
}),
|
||||
|
||||
/**
|
||||
* Returns information from the form about fields that can be autofilled, and
|
||||
* populates the fieldDetails array on this object accordingly.
|
||||
*
|
||||
* @returns Serializable data structure that can be sent to the user
|
||||
* interface, or null if the operation failed because the constraints
|
||||
* on the allowed fields were not honored.
|
||||
*/
|
||||
collectFormFields: function () {
|
||||
let autofillData = {
|
||||
sections: [],
|
||||
};
|
||||
@ -92,6 +131,22 @@ FormHandler.prototype = {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store the association between the field metadata and the element.
|
||||
if (this.fieldDetails.some(f => f.section == info.section &&
|
||||
f.addressType == info.addressType &&
|
||||
f.contactType == info.contactType &&
|
||||
f.fieldName == info.fieldName)) {
|
||||
// A field with the same identifier already exists.
|
||||
return null;
|
||||
}
|
||||
this.fieldDetails.push({
|
||||
section: info.section,
|
||||
addressType: info.addressType,
|
||||
contactType: info.contactType,
|
||||
fieldName: info.fieldName,
|
||||
element: element,
|
||||
});
|
||||
|
||||
// The first level is the custom section.
|
||||
let section = autofillData.sections
|
||||
.find(s => s.name == info.section);
|
||||
@ -125,6 +180,38 @@ FormHandler.prototype = {
|
||||
return autofillData;
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes form fields that can be autofilled, and populates them with the
|
||||
* data provided by RequestAutocompleteUI.
|
||||
*
|
||||
* @param aAutofillResult
|
||||
* Data returned by the user interface.
|
||||
* {
|
||||
* fields: [
|
||||
* section: Value originally provided to the user interface.
|
||||
* addressType: Value originally provided to the user interface.
|
||||
* contactType: Value originally provided to the user interface.
|
||||
* fieldName: Value originally provided to the user interface.
|
||||
* value: String with which the field should be updated.
|
||||
* ],
|
||||
* }
|
||||
*/
|
||||
autofillFormFields: function (aAutofillResult) {
|
||||
for (let field of aAutofillResult.fields) {
|
||||
// Get the field details, if it was processed by the user interface.
|
||||
let fieldDetail = this.fieldDetails
|
||||
.find(f => f.section == field.section &&
|
||||
f.addressType == field.addressType &&
|
||||
f.contactType == field.contactType &&
|
||||
f.fieldName == field.fieldName);
|
||||
if (!fieldDetail) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fieldDetail.element.value = field.value;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Waits for one tick of the event loop before resolving the returned promise.
|
||||
*/
|
||||
|
@ -26,11 +26,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
* Handles the requestAutocomplete user interface.
|
||||
*/
|
||||
this.RequestAutocompleteUI = function (aAutofillData) {
|
||||
Services.console.logStringMessage("rAc UI request: " +
|
||||
JSON.stringify(aAutofillData));
|
||||
this._autofillData = aAutofillData;
|
||||
}
|
||||
|
||||
this.RequestAutocompleteUI.prototype = {
|
||||
_autofillData: null,
|
||||
|
||||
show: Task.async(function* () {
|
||||
// Create a new promise and store the function that will resolve it. This
|
||||
// will be called by the UI once the selection has been made.
|
||||
@ -38,7 +39,10 @@ this.RequestAutocompleteUI.prototype = {
|
||||
let uiPromise = new Promise(resolve => resolveFn = resolve);
|
||||
|
||||
// Wrap the callback function so that it survives XPCOM.
|
||||
let args = { resolveFn: resolveFn };
|
||||
let args = {
|
||||
resolveFn: resolveFn,
|
||||
autofillData: this._autofillData,
|
||||
};
|
||||
args.wrappedJSObject = args;
|
||||
|
||||
// Open the window providing the function to call when it closes.
|
||||
|
@ -20,10 +20,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
|
||||
const RequestAutocompleteDialog = {
|
||||
resolveFn: null,
|
||||
autofillData: null,
|
||||
|
||||
onLoad: function () {
|
||||
Task.spawn(function* () {
|
||||
this.resolveFn = window.arguments[0].wrappedJSObject.resolveFn;
|
||||
let args = window.arguments[0].wrappedJSObject;
|
||||
this.resolveFn = args.resolveFn;
|
||||
this.autofillData = args.autofillData;
|
||||
|
||||
window.sizeToContent();
|
||||
|
||||
@ -33,8 +36,46 @@ const RequestAutocompleteDialog = {
|
||||
},
|
||||
|
||||
onAccept: function () {
|
||||
// TODO: Replace with autofill storage module (bug 1018304).
|
||||
const dummyDB = {
|
||||
"": {
|
||||
"name": "Mozzy La",
|
||||
"street-address": "331 E Evelyn Ave",
|
||||
"address-level2": "Mountain View",
|
||||
"address-level1": "CA",
|
||||
"country": "US",
|
||||
"postal-code": "94041",
|
||||
"email": "email@example.org",
|
||||
}
|
||||
};
|
||||
|
||||
let result = { fields: [] };
|
||||
for (let section of this.autofillData.sections) {
|
||||
for (let addressSection of section.addressSections) {
|
||||
let addressType = addressSection.addressType;
|
||||
if (!(addressType in dummyDB)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let field of addressSection.fields) {
|
||||
let fieldName = field.fieldName;
|
||||
if (!(fieldName in dummyDB[addressType])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.fields.push({
|
||||
section: section.name,
|
||||
addressType: addressType,
|
||||
contactType: field.contactType,
|
||||
fieldName: field.fieldName,
|
||||
value: dummyDB[addressType][fieldName],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.close();
|
||||
this.resolveFn({ email: "email@example.org" });
|
||||
this.resolveFn(result);
|
||||
},
|
||||
|
||||
onCancel: function () {
|
||||
|
@ -13,15 +13,20 @@
|
||||
*/
|
||||
add_task(function* test_select_profile() {
|
||||
// Request an e-mail address.
|
||||
let data = { "": { "": { "email": null } } };
|
||||
let { uiWindow, promiseResult } = yield FormAutofillTest.showUI(data);
|
||||
let { uiWindow, promiseResult } = yield FormAutofillTest.showUI(
|
||||
TestData.requestEmailOnly);
|
||||
|
||||
// Accept the dialog.
|
||||
let acceptButton = uiWindow.document.getElementById("accept");
|
||||
EventUtils.synthesizeMouseAtCenter(acceptButton, {}, uiWindow);
|
||||
|
||||
let result = yield promiseResult;
|
||||
Assert.equal(result.email, "email@example.org");
|
||||
Assert.equal(result.fields.length, 1);
|
||||
Assert.equal(result.fields[0].section, "");
|
||||
Assert.equal(result.fields[0].addressType, "");
|
||||
Assert.equal(result.fields[0].contactType, "");
|
||||
Assert.equal(result.fields[0].fieldName, "email");
|
||||
Assert.equal(result.fields[0].value, "email@example.org");
|
||||
});
|
||||
|
||||
/**
|
||||
@ -29,8 +34,8 @@ add_task(function* test_select_profile() {
|
||||
*/
|
||||
add_task(function* test_cancel() {
|
||||
// Request an e-mail address.
|
||||
let data = { "": { "": { "email": null } } };
|
||||
let { uiWindow, promiseResult } = yield FormAutofillTest.showUI(data);
|
||||
let { uiWindow, promiseResult } = yield FormAutofillTest.showUI(
|
||||
TestData.requestEmailOnly);
|
||||
|
||||
// Cancel the dialog.
|
||||
let acceptButton = uiWindow.document.getElementById("cancel");
|
||||
|
@ -193,7 +193,8 @@ let FormAutofillTest = {
|
||||
// Wait for the initialization event before opening the window.
|
||||
let promiseUIWindow =
|
||||
TestUtils.waitForNotification("formautofill-window-initialized");
|
||||
let ui = yield FormAutofill.integration.createRequestAutocompleteUI({});
|
||||
let ui = yield FormAutofill.integration.createRequestAutocompleteUI(
|
||||
aFormAutofillData);
|
||||
let promiseResult = ui.show();
|
||||
|
||||
// The window is the subject of the observer notification.
|
||||
@ -204,6 +205,26 @@ let FormAutofillTest = {
|
||||
}),
|
||||
};
|
||||
|
||||
let TestData = {
|
||||
/**
|
||||
* Autofill UI request for the e-mail field only.
|
||||
*/
|
||||
get requestEmailOnly() {
|
||||
return {
|
||||
sections: [{
|
||||
name: "",
|
||||
addressSections: [{
|
||||
addressType: "",
|
||||
fields: [{
|
||||
fieldName: "email",
|
||||
contactType: "",
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/* --- Initialization and termination functions common to all tests --- */
|
||||
|
||||
add_task(function* test_common_initialize() {
|
||||
|
Loading…
Reference in New Issue
Block a user