mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 862442 - Use a content script to listen for input and change events; r=yoric
This commit is contained in:
parent
3d11af6229
commit
268d8cd42f
@ -12,8 +12,12 @@ function debug(msg) {
|
||||
*/
|
||||
let EventListener = {
|
||||
|
||||
DOM_EVENTS: [
|
||||
"pageshow", "change", "input"
|
||||
],
|
||||
|
||||
init: function () {
|
||||
addEventListener("pageshow", this, true);
|
||||
this.DOM_EVENTS.forEach(e => addEventListener(e, this, true));
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
@ -22,6 +26,10 @@ let EventListener = {
|
||||
if (event.persisted)
|
||||
sendAsyncMessage("SessionStore:pageshow");
|
||||
break;
|
||||
case "input":
|
||||
case "change":
|
||||
sendAsyncMessage("SessionStore:input");
|
||||
break;
|
||||
default:
|
||||
debug("received unknown event '" + event.type + "'");
|
||||
break;
|
||||
|
@ -62,6 +62,18 @@ const CAPABILITIES = [
|
||||
"DNSPrefetch", "Auth", "WindowControl"
|
||||
];
|
||||
|
||||
const MESSAGES = [
|
||||
// The content script tells us that its form data (or that of one of its
|
||||
// subframes) might have changed. This can be the contents or values of
|
||||
// standard form fields or of ContentEditables.
|
||||
"SessionStore:input",
|
||||
|
||||
// The content script has received a pageshow event. This happens when a
|
||||
// page is loaded from bfcache without any network activity, i.e. when
|
||||
// clicking the back or forward button.
|
||||
"SessionStore:pageshow"
|
||||
];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
const TAB_EVENTS = [
|
||||
"TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide", "TabPinned",
|
||||
@ -621,6 +633,9 @@ let SessionStoreInternal = {
|
||||
case "SessionStore:pageshow":
|
||||
this.onTabLoad(win, browser);
|
||||
break;
|
||||
case "SessionStore:input":
|
||||
this.onTabInput(win, browser);
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + aMessage.name + "'");
|
||||
break;
|
||||
@ -646,11 +661,6 @@ let SessionStoreInternal = {
|
||||
this.restoreDocument(win, browser, aEvent);
|
||||
this.onTabLoad(win, browser);
|
||||
break;
|
||||
case "change":
|
||||
case "input":
|
||||
case "DOMAutoComplete":
|
||||
this.onTabInput(win, aEvent.currentTarget);
|
||||
break;
|
||||
case "TabOpen":
|
||||
this.onTabAdd(win, aEvent.originalTarget);
|
||||
break;
|
||||
@ -1212,11 +1222,9 @@ let SessionStoreInternal = {
|
||||
onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("load", this, true);
|
||||
browser.addEventListener("change", this, true);
|
||||
browser.addEventListener("input", this, true);
|
||||
browser.addEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
browser.messageManager.addMessageListener("SessionStore:pageshow", this);
|
||||
let mm = browser.messageManager;
|
||||
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
@ -1237,11 +1245,9 @@ let SessionStoreInternal = {
|
||||
onTabRemove: function ssi_onTabRemove(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.removeEventListener("load", this, true);
|
||||
browser.removeEventListener("change", this, true);
|
||||
browser.removeEventListener("input", this, true);
|
||||
browser.removeEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
browser.messageManager.removeMessageListener("SessionStore:pageshow", this);
|
||||
let mm = browser.messageManager;
|
||||
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
|
||||
|
||||
delete browser.__SS_data;
|
||||
delete browser.__SS_tabStillLoading;
|
||||
@ -2254,16 +2260,8 @@ let SessionStoreInternal = {
|
||||
}
|
||||
|
||||
// designMode is undefined e.g. for XUL documents (as about:config)
|
||||
if ((aContent.document.designMode || "") == "on" && aContent.document.body) {
|
||||
if (aData.innerHTML === undefined && !aFullData) {
|
||||
// we get no "input" events from iframes - listen for keypress here
|
||||
let _this = this;
|
||||
aContent.addEventListener("keypress", function(aEvent) {
|
||||
_this.saveStateDelayed(aWindow, 3000);
|
||||
}, true);
|
||||
}
|
||||
if ((aContent.document.designMode || "") == "on" && aContent.document.body)
|
||||
aData.innerHTML = aContent.document.body.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
// get scroll position from nsIDOMWindowUtils, since it allows avoiding a
|
||||
|
@ -25,6 +25,8 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_form_restore_events_sample.html \
|
||||
browser_formdata_format.js \
|
||||
browser_formdata_format_sample.html \
|
||||
browser_input.js \
|
||||
browser_input_sample.html \
|
||||
browser_pageshow.js \
|
||||
browser_248970_b_perwindowpb.js \
|
||||
browser_248970_b_sample.html \
|
||||
|
121
browser/components/sessionstore/test/browser_input.js
Normal file
121
browser/components/sessionstore/test/browser_input.js
Normal file
@ -0,0 +1,121 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const URL = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_input_sample.html";
|
||||
|
||||
function test() {
|
||||
TestRunner.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that modifying form input fields on a web page marks the
|
||||
* window as dirty and causes the corresponding form data of the tab that
|
||||
* changed to be re-collected.
|
||||
*/
|
||||
|
||||
function runTests() {
|
||||
// Create a dummy window that is regarded as active. We need to do this
|
||||
// because we always collect data for tabs of active windows no matter if
|
||||
// the window is dirty or not.
|
||||
let win = OpenBrowserWindow();
|
||||
yield waitForLoad(win);
|
||||
|
||||
// Create a tab with some form fields.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
yield waitForLoad(browser);
|
||||
|
||||
// All windows currently marked as dirty will be written to disk
|
||||
// and thus marked clean afterwards.
|
||||
yield forceWriteState();
|
||||
|
||||
// Modify the checkbox field's state.
|
||||
let chk = browser.contentDocument.getElementById("chk");
|
||||
EventUtils.sendMouseEvent({type: "click"}, chk);
|
||||
yield waitForInput();
|
||||
|
||||
// Check that we'll save the form data state correctly.
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let {formdata} = state.windows[0].tabs[1].entries[0];
|
||||
is(formdata.id.chk, true, "chk's value is correct");
|
||||
|
||||
// Clear dirty state of all windows again.
|
||||
yield forceWriteState();
|
||||
|
||||
// Modify the text input field's state.
|
||||
browser.contentDocument.getElementById("txt").focus();
|
||||
EventUtils.synthesizeKey("m", {});
|
||||
yield waitForInput();
|
||||
|
||||
// Check that we'll save the form data state correctly.
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let {formdata} = state.windows[0].tabs[1].entries[0];
|
||||
is(formdata.id.chk, true, "chk's value is correct");
|
||||
is(formdata.id.txt, "m", "txt's value is correct");
|
||||
|
||||
// Clear dirty state of all windows again.
|
||||
yield forceWriteState();
|
||||
|
||||
// Modify the state of the checkbox contained in the iframe.
|
||||
let cdoc = browser.contentDocument.getElementById("ifr").contentDocument;
|
||||
EventUtils.sendMouseEvent({type: "click"}, cdoc.getElementById("chk"));
|
||||
yield waitForInput();
|
||||
|
||||
// Modify the state of text field contained in the iframe.
|
||||
cdoc.getElementById("txt").focus();
|
||||
EventUtils.synthesizeKey("m", {});
|
||||
yield waitForInput();
|
||||
|
||||
// Check that we'll save the iframe's form data correctly.
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let {formdata} = state.windows[0].tabs[1].entries[0].children[0];
|
||||
is(formdata.id.chk, true, "iframe chk's value is correct");
|
||||
is(formdata.id.txt, "m", "iframe txt's value is correct");
|
||||
|
||||
// Clear dirty state of all windows again.
|
||||
yield forceWriteState();
|
||||
|
||||
// Modify the content editable's state.
|
||||
browser.contentDocument.getElementById("ced").focus();
|
||||
EventUtils.synthesizeKey("m", {});
|
||||
yield waitForInput();
|
||||
|
||||
// Check the we'll correctly save the content editable's state.
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
let {innerHTML} = state.windows[0].tabs[1].entries[0].children[1];
|
||||
is(innerHTML, "m", "content editable's value is correct");
|
||||
|
||||
// Clean up after ourselves.
|
||||
gBrowser.removeTab(tab);
|
||||
win.close();
|
||||
}
|
||||
|
||||
function forceWriteState() {
|
||||
const PREF = "browser.sessionstore.interval";
|
||||
const TOPIC = "sessionstore-state-write";
|
||||
|
||||
Services.obs.addObserver(function observe() {
|
||||
Services.obs.removeObserver(observe, TOPIC);
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
executeSoon(next);
|
||||
}, TOPIC, false);
|
||||
|
||||
Services.prefs.setIntPref(PREF, 0);
|
||||
}
|
||||
|
||||
function waitForLoad(aElement) {
|
||||
aElement.addEventListener("load", function onLoad() {
|
||||
aElement.removeEventListener("load", onLoad, true);
|
||||
executeSoon(next);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function waitForInput() {
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.addMessageListener("SessionStore:input", function onPageShow() {
|
||||
mm.removeMessageListener("SessionStore:input", onPageShow);
|
||||
executeSoon(next);
|
||||
});
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html dir="ltr" xml:lang="en-US" lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>sessionstore input test</title>
|
||||
</head>
|
||||
<body>
|
||||
<input id="chk" type="checkbox" /><input id="txt" />
|
||||
<iframe id="ifr" src="data:text/html;charset=utf-8,<input id=chk type=checkbox /><input id=txt />"></iframe>
|
||||
<iframe id="ced"></iframe>
|
||||
|
||||
<script type="text/javascript">
|
||||
addEventListener("load", () => {
|
||||
document.getElementById("ced").contentDocument.designMode = "on";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user