зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1589938
, convert FormHistory modules into JSWindowActors, allowing the test test_form_submission.html to work with fission enabled, r=MattN
Differential Revision: https://phabricator.services.mozilla.com/D49969 --HG-- rename : toolkit/components/satchel/FormSubmitChild.jsm => toolkit/components/satchel/FormHistoryChild.jsm extra : moz-landing-system : lando
This commit is contained in:
Родитель
44f6080af9
Коммит
41f434a1d8
|
@ -39,9 +39,8 @@ function isAutocompleteDisabled(aField) {
|
|||
function FormHistoryClient({ formField, inputName }) {
|
||||
if (formField && inputName != this.SEARCHBAR_ID) {
|
||||
let window = formField.ownerGlobal;
|
||||
this.mm = window.docShell.messageManager;
|
||||
} else {
|
||||
if (inputName == this.SEARCHBAR_ID && formField) {
|
||||
this.windowGlobal = window.getWindowGlobalChild();
|
||||
} else if (inputName == this.SEARCHBAR_ID && formField) {
|
||||
throw new Error(
|
||||
"FormHistoryClient constructed with both a " +
|
||||
"formField and an inputName. This is not " +
|
||||
|
@ -49,8 +48,6 @@ function FormHistoryClient({ formField, inputName }) {
|
|||
"returned."
|
||||
);
|
||||
}
|
||||
this.mm = Services.cpmm;
|
||||
}
|
||||
|
||||
this.inputName = inputName;
|
||||
this.id = FormHistoryClient.nextRequestID++;
|
||||
|
@ -59,15 +56,16 @@ function FormHistoryClient({ formField, inputName }) {
|
|||
FormHistoryClient.prototype = {
|
||||
SEARCHBAR_ID: "searchbar-history",
|
||||
|
||||
// It is assumed that nsFormAutoComplete only uses / cares about
|
||||
// one FormHistoryClient at a time, and won't attempt to have
|
||||
// multiple in-flight searches occurring with the same FormHistoryClient.
|
||||
// We use an ID number per instantiated FormHistoryClient to make
|
||||
// sure we only respond to messages that were meant for us.
|
||||
id: 0,
|
||||
callback: null,
|
||||
cancelled: false,
|
||||
inputName: "",
|
||||
mm: null,
|
||||
|
||||
getActor() {
|
||||
if (this.windowGlobal) {
|
||||
return this.windowGlobal.getActor("FormHistory");
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Query FormHistory for some results.
|
||||
|
@ -83,14 +81,50 @@ FormHistoryClient.prototype = {
|
|||
* argument (the found entries).
|
||||
*/
|
||||
requestAutoCompleteResults(searchString, params, callback) {
|
||||
this.mm.sendAsyncMessage("FormHistory:AutoCompleteSearchAsync", {
|
||||
this.cancelled = false;
|
||||
|
||||
// Use the actor if possible, otherwise for the searchbar,
|
||||
// use the more roundabout per-process message manager which has
|
||||
// no sendQuery method.
|
||||
let actor = this.getActor();
|
||||
if (actor) {
|
||||
actor
|
||||
.sendQuery("FormHistory:AutoCompleteSearchAsync", {
|
||||
searchString,
|
||||
params,
|
||||
})
|
||||
.then(
|
||||
results => {
|
||||
this.handleAutoCompleteResults(results, callback);
|
||||
},
|
||||
() => this.cancel()
|
||||
);
|
||||
} else {
|
||||
this.callback = callback;
|
||||
Services.cpmm.addMessageListener(
|
||||
"FormHistory:AutoCompleteSearchResults",
|
||||
this
|
||||
);
|
||||
Services.cpmm.sendAsyncMessage("FormHistory:AutoCompleteSearchAsync", {
|
||||
id: this.id,
|
||||
searchString,
|
||||
params,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
this.mm.addMessageListener("FormHistory:AutoCompleteSearchResults", this);
|
||||
this.callback = callback;
|
||||
handleAutoCompleteResults(results, callback) {
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
Cu.reportError("FormHistoryClient received response with no callback");
|
||||
return;
|
||||
}
|
||||
|
||||
callback(results);
|
||||
this.cancel();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -99,7 +133,14 @@ FormHistoryClient.prototype = {
|
|||
* called from this FormHistoryClient.
|
||||
*/
|
||||
cancel() {
|
||||
this.clearListeners();
|
||||
if (this.callback) {
|
||||
Services.cpmm.removeMessageListener(
|
||||
"FormHistory:AutoCompleteSearchResults",
|
||||
this
|
||||
);
|
||||
this.callback = null;
|
||||
}
|
||||
this.cancelled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -115,34 +156,19 @@ FormHistoryClient.prototype = {
|
|||
* The guid for the item being removed.
|
||||
*/
|
||||
remove(value, guid) {
|
||||
this.mm.sendAsyncMessage("FormHistory:RemoveEntry", {
|
||||
let actor = this.getActor() || Services.cpmm;
|
||||
actor.sendAsyncMessage("FormHistory:RemoveEntry", {
|
||||
inputName: this.inputName,
|
||||
value,
|
||||
guid,
|
||||
});
|
||||
},
|
||||
|
||||
// Private methods
|
||||
|
||||
receiveMessage(msg) {
|
||||
let { id, results } = msg.data;
|
||||
if (id != this.id) {
|
||||
return;
|
||||
if (id == this.id) {
|
||||
this.handleAutoCompleteResults(results, this.callback);
|
||||
}
|
||||
if (!this.callback) {
|
||||
Cu.reportError("FormHistoryClient received message with no callback");
|
||||
return;
|
||||
}
|
||||
this.callback(results);
|
||||
this.clearListeners();
|
||||
},
|
||||
|
||||
clearListeners() {
|
||||
this.mm.removeMessageListener(
|
||||
"FormHistory:AutoCompleteSearchResults",
|
||||
this
|
||||
);
|
||||
this.callback = null;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["FormSubmitChild"];
|
||||
var EXPORTED_SYMBOLS = ["FormHistoryChild"];
|
||||
|
||||
const { ActorChild } = ChromeUtils.import(
|
||||
"resource://gre/modules/ActorChild.jsm"
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -22,46 +22,18 @@ ChromeUtils.defineModuleGetter(
|
|||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
);
|
||||
|
||||
class FormSubmitChild extends ActorChild {
|
||||
constructor(dispatcher) {
|
||||
super(dispatcher);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gDebug", "browser.formfill.debug");
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gEnabled", "browser.formfill.enable");
|
||||
|
||||
this.QueryInterface = ChromeUtils.generateQI([
|
||||
Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference,
|
||||
]);
|
||||
|
||||
Services.prefs.addObserver("browser.formfill.", this);
|
||||
this.updatePrefs();
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
Services.prefs.removeObserver("browser.formfill.", this);
|
||||
}
|
||||
|
||||
updatePrefs() {
|
||||
this.debug = Services.prefs.getBoolPref("browser.formfill.debug");
|
||||
this.enabled = Services.prefs.getBoolPref("browser.formfill.enable");
|
||||
}
|
||||
|
||||
log(message) {
|
||||
if (!this.debug) {
|
||||
function log(message) {
|
||||
if (!gDebug) {
|
||||
return;
|
||||
}
|
||||
dump("satchelFormListener: " + message + "\n");
|
||||
Services.console.logStringMessage("satchelFormListener: " + message);
|
||||
}
|
||||
|
||||
/* ---- nsIObserver interface ---- */
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "nsPref:changed") {
|
||||
this.updatePrefs();
|
||||
} else {
|
||||
this.log("Oops! Unexpected notification: " + topic);
|
||||
}
|
||||
}
|
||||
|
||||
class FormHistoryChild extends JSWindowActorChild {
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "DOMFormBeforeSubmit": {
|
||||
|
@ -77,13 +49,13 @@ class FormSubmitChild extends ActorChild {
|
|||
onDOMFormBeforeSubmit(event) {
|
||||
let form = event.target;
|
||||
if (
|
||||
!this.enabled ||
|
||||
!gEnabled ||
|
||||
PrivateBrowsingUtils.isContentWindowPrivate(form.ownerGlobal)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.log("Form submit observer notified.");
|
||||
log("Form submit observer notified.");
|
||||
|
||||
if (
|
||||
form.hasAttribute("autocomplete") &&
|
||||
|
@ -127,7 +99,7 @@ class FormSubmitChild extends ActorChild {
|
|||
|
||||
// Don't save credit card numbers.
|
||||
if (CreditCard.isValidNumber(value)) {
|
||||
this.log("skipping saving a credit card number");
|
||||
log("skipping saving a credit card number");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -137,19 +109,19 @@ class FormSubmitChild extends ActorChild {
|
|||
}
|
||||
|
||||
if (name == "searchbar-history") {
|
||||
this.log('addEntry for input name "' + name + '" is denied');
|
||||
log('addEntry for input name "' + name + '" is denied');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Limit stored data to 200 characters.
|
||||
if (name.length > 200 || value.length > 200) {
|
||||
this.log("skipping input that has a name/value too large");
|
||||
log("skipping input that has a name/value too large");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Limit number of fields stored per form.
|
||||
if (entries.length >= 100) {
|
||||
this.log("not saving any more entries for this form.");
|
||||
log("not saving any more entries for this form.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -157,7 +129,7 @@ class FormSubmitChild extends ActorChild {
|
|||
}
|
||||
|
||||
if (entries.length) {
|
||||
this.log("sending entries to parent process for form " + form.id);
|
||||
log("sending entries to parent process for form " + form.id);
|
||||
this.sendAsyncMessage("FormHistory:FormSubmitEntries", entries);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["FormHistoryParent"];
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm"
|
||||
);
|
||||
|
||||
class FormHistoryParent extends JSWindowActorParent {
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "FormHistory:FormSubmitEntries": {
|
||||
let entries = message.data;
|
||||
let changes = entries.map(entry => ({
|
||||
op: "bump",
|
||||
fieldname: entry.name,
|
||||
value: entry.value,
|
||||
}));
|
||||
|
||||
FormHistory.update(changes);
|
||||
break;
|
||||
}
|
||||
|
||||
case "FormHistory:AutoCompleteSearchAsync":
|
||||
return this.autoCompleteSearch(message);
|
||||
|
||||
case "FormHistory:RemoveEntry":
|
||||
this.removeEntry(message);
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
autoCompleteSearch(message) {
|
||||
let { searchString, params } = message.data;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let results = [];
|
||||
let processResults = {
|
||||
handleResult: aResult => {
|
||||
results.push(aResult);
|
||||
},
|
||||
handleCompletion: aReason => {
|
||||
if (!aReason) {
|
||||
resolve(results);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
FormHistory.getAutoCompleteResults(searchString, params, processResults);
|
||||
});
|
||||
}
|
||||
|
||||
removeEntry(message) {
|
||||
let { inputName, value, guid } = message.data;
|
||||
FormHistory.update({
|
||||
op: "remove",
|
||||
fieldname: inputName,
|
||||
value,
|
||||
guid,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -50,32 +50,20 @@ FormHistoryStartup.prototype = {
|
|||
Services.obs.addObserver(this, "idle-daily", true);
|
||||
Services.obs.addObserver(this, "formhistory-expire-now", true);
|
||||
|
||||
Services.mm.addMessageListener("FormHistory:FormSubmitEntries", this);
|
||||
|
||||
// For each of these messages, we could receive them from content,
|
||||
// or we might receive them from the ppmm if the searchbar is
|
||||
// having its history queried.
|
||||
for (let manager of [Services.mm, Services.ppmm]) {
|
||||
manager.addMessageListener("FormHistory:AutoCompleteSearchAsync", this);
|
||||
manager.addMessageListener("FormHistory:RemoveEntry", this);
|
||||
}
|
||||
Services.ppmm.addMessageListener(
|
||||
"FormHistory:AutoCompleteSearchAsync",
|
||||
this
|
||||
);
|
||||
Services.ppmm.addMessageListener("FormHistory:RemoveEntry", this);
|
||||
},
|
||||
|
||||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "FormHistory:FormSubmitEntries": {
|
||||
let entries = message.data;
|
||||
let changes = entries.map(entry => ({
|
||||
op: "bump",
|
||||
fieldname: entry.name,
|
||||
value: entry.value,
|
||||
}));
|
||||
|
||||
FormHistory.update(changes);
|
||||
break;
|
||||
}
|
||||
|
||||
case "FormHistory:AutoCompleteSearchAsync": {
|
||||
// This case is only used for the search field. There is a
|
||||
// similar algorithm in FormHistoryParent.jsm that uses
|
||||
// sendQuery for other form fields.
|
||||
|
||||
let { id, searchString, params } = message.data;
|
||||
|
||||
if (this.pendingQuery) {
|
||||
|
@ -83,19 +71,7 @@ FormHistoryStartup.prototype = {
|
|||
this.pendingQuery = null;
|
||||
}
|
||||
|
||||
let mm;
|
||||
let query = null;
|
||||
// MessageListenerManager is a Mozilla-only interface, so disable the eslint error
|
||||
// for it.
|
||||
// eslint-disable-next-line no-undef
|
||||
if (message.target instanceof MessageListenerManager) {
|
||||
// The target is the PPMM, meaning that the parent process
|
||||
// is requesting FormHistory data on the searchbar.
|
||||
mm = message.target;
|
||||
} else {
|
||||
// Otherwise, the target is a <xul:browser>.
|
||||
mm = message.target.messageManager;
|
||||
}
|
||||
|
||||
let results = [];
|
||||
let processResults = {
|
||||
|
@ -109,10 +85,13 @@ FormHistoryStartup.prototype = {
|
|||
if (query === this.pendingQuery) {
|
||||
this.pendingQuery = null;
|
||||
if (!aReason) {
|
||||
mm.sendAsyncMessage("FormHistory:AutoCompleteSearchResults", {
|
||||
message.target.sendAsyncMessage(
|
||||
"FormHistory:AutoCompleteSearchResults",
|
||||
{
|
||||
id,
|
||||
results,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -42,7 +42,8 @@ XPCOM_MANIFESTS += [
|
|||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_TARGET_FILES.actors += [
|
||||
'FormSubmitChild.jsm',
|
||||
'FormHistoryChild.jsm',
|
||||
'FormHistoryParent.jsm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -16,7 +16,6 @@ skip-if = (verify && debug && (os == 'win')) || (os == 'mac') # Bug 1514249
|
|||
[test_form_autocomplete_validation_at_input_event.html]
|
||||
[test_form_autocomplete_with_list.html]
|
||||
[test_form_submission.html]
|
||||
fail-if = fission
|
||||
[test_form_submission_cap.html]
|
||||
[test_form_submission_cap2.html]
|
||||
[test_input_valid_state_with_autocomplete.html]
|
||||
|
|
|
@ -6,23 +6,12 @@
|
|||
|
||||
<body>
|
||||
|
||||
<form id="subform2" onsubmit="return checkSubmit(100)">
|
||||
<form id="subform2" onsubmit="return false">
|
||||
<input id="subtest2" type="text" name="subtest2">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
/* exported checkSubmit clickButton */
|
||||
function checkSubmit(num) {
|
||||
return SpecialPowers.wrap(parent).wrappedJSObject.checkSubmit(num);
|
||||
}
|
||||
|
||||
function clickButton(num) {
|
||||
if (num == 100) {
|
||||
document.querySelectorAll("button")[0].click();
|
||||
}
|
||||
}
|
||||
|
||||
// set the input's value (can't use a default value, as satchel will ignore it)
|
||||
document.getElementById("subtest2").value = "subtestValue";
|
||||
</script>
|
||||
|
|
|
@ -490,8 +490,18 @@ function submitForm(formNum) {
|
|||
// from an HTTPS domain in an iframe.
|
||||
if (nextFormNum == 100) {
|
||||
ok(true, "submitting iframe test " + nextFormNum);
|
||||
SpecialPowers.wrap(document.getElementById("iframe").contentWindow)
|
||||
.wrappedJSObject.clickButton(nextFormNum);
|
||||
|
||||
// Need to call checkSubmit first, as the iframe's document can be in another
|
||||
// process and won't be able to notify back before the submit occurs.
|
||||
checkSubmit(100);
|
||||
|
||||
let browsingContext = SpecialPowers.unwrap(
|
||||
SpecialPowers.wrap(document.getElementById("iframe")).browsingContext);
|
||||
SpecialPowers.spawn(browsingContext, [], () => {
|
||||
/* eslint-disable no-undef */
|
||||
content.document.querySelectorAll("button")[0].click();
|
||||
/* eslint-enable no-undef */
|
||||
});
|
||||
} else {
|
||||
let button = getFormSubmitButton(nextFormNum);
|
||||
button.click();
|
||||
|
|
|
@ -263,6 +263,20 @@ let ACTORS = {
|
|||
allFrames: true,
|
||||
},
|
||||
|
||||
FormHistory: {
|
||||
parent: {
|
||||
moduleURI: "resource://gre/actors/FormHistoryParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource://gre/actors/FormHistoryChild.jsm",
|
||||
events: {
|
||||
DOMFormBeforeSubmit: {},
|
||||
},
|
||||
},
|
||||
|
||||
allFrames: true,
|
||||
},
|
||||
|
||||
InlineSpellChecker: {
|
||||
parent: {
|
||||
moduleURI: "resource://gre/actors/InlineSpellCheckerParent.jsm",
|
||||
|
@ -367,16 +381,6 @@ let LEGACY_ACTORS = {
|
|||
},
|
||||
},
|
||||
|
||||
FormSubmit: {
|
||||
child: {
|
||||
module: "resource://gre/actors/FormSubmitChild.jsm",
|
||||
allFrames: true,
|
||||
events: {
|
||||
DOMFormBeforeSubmit: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
KeyPressEventModelChecker: {
|
||||
child: {
|
||||
module: "resource://gre/actors/KeyPressEventModelCheckerChild.jsm",
|
||||
|
|
Загрузка…
Ссылка в новой задаче