mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 861409 - Use a content script to listen for pageshow events; r=yoric,jaws
This commit is contained in:
parent
13d8b090f4
commit
6123af3720
@ -760,6 +760,7 @@ var gBrowserInit = {
|
||||
window.addEventListener("AppCommand", HandleAppCommandEvent, true);
|
||||
|
||||
messageManager.loadFrameScript("chrome://browser/content/content.js", true);
|
||||
messageManager.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
|
||||
|
||||
// initialize observers and listeners
|
||||
// and give C++ access to gBrowser
|
||||
|
@ -0,0 +1,32 @@
|
||||
/* 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/. */
|
||||
|
||||
function debug(msg) {
|
||||
Services.console.logStringMessage("SessionStoreContent: " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for and handles content events that we need for the
|
||||
* session store service to be notified of state changes in content.
|
||||
*/
|
||||
let EventListener = {
|
||||
|
||||
init: function () {
|
||||
addEventListener("pageshow", this, true);
|
||||
},
|
||||
|
||||
handleEvent: function (event) {
|
||||
switch (event.type) {
|
||||
case "pageshow":
|
||||
if (event.persisted)
|
||||
sendAsyncMessage("SessionStore:pageshow");
|
||||
break;
|
||||
default:
|
||||
debug("received unknown event '" + event.type + "'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EventListener.init();
|
@ -5,3 +5,4 @@
|
||||
browser.jar:
|
||||
* content/browser/aboutSessionRestore.xhtml (content/aboutSessionRestore.xhtml)
|
||||
* content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js)
|
||||
content/browser/content-sessionStore.js (content/content-sessionStore.js)
|
||||
|
@ -609,6 +609,26 @@ let SessionStoreInternal = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* This method handles incoming messages sent by the session store content
|
||||
* script and thus enables communication with OOP tabs.
|
||||
*/
|
||||
receiveMessage: function ssi_receiveMessage(aMessage) {
|
||||
var browser = aMessage.target;
|
||||
var win = browser.ownerDocument.defaultView;
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "SessionStore:pageshow":
|
||||
this.onTabLoad(win, browser);
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + aMessage.name + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
this._clearRestoringWindows();
|
||||
},
|
||||
|
||||
/* ........ Window Event Handlers .............. */
|
||||
|
||||
/**
|
||||
@ -621,11 +641,10 @@ let SessionStoreInternal = {
|
||||
// If __SS_restore_data is set, then we need to restore the document
|
||||
// (form data, scrolling, etc.). This will only happen when a tab is
|
||||
// first restored.
|
||||
if (aEvent.currentTarget.__SS_restore_data)
|
||||
this.restoreDocument(win, aEvent.currentTarget, aEvent);
|
||||
// We still need to call onTabLoad, so fall through to "pageshow" case.
|
||||
case "pageshow":
|
||||
this.onTabLoad(win, aEvent.currentTarget, aEvent);
|
||||
let browser = aEvent.currentTarget;
|
||||
if (browser.__SS_restore_data)
|
||||
this.restoreDocument(win, browser, aEvent);
|
||||
this.onTabLoad(win, browser);
|
||||
break;
|
||||
case "change":
|
||||
case "input":
|
||||
@ -1193,11 +1212,12 @@ let SessionStoreInternal = {
|
||||
onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("load", this, true);
|
||||
browser.addEventListener("pageshow", this, true);
|
||||
browser.addEventListener("change", this, true);
|
||||
browser.addEventListener("input", this, true);
|
||||
browser.addEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
browser.messageManager.addMessageListener("SessionStore:pageshow", this);
|
||||
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
@ -1217,11 +1237,12 @@ let SessionStoreInternal = {
|
||||
onTabRemove: function ssi_onTabRemove(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.removeEventListener("load", this, true);
|
||||
browser.removeEventListener("pageshow", this, true);
|
||||
browser.removeEventListener("change", this, true);
|
||||
browser.removeEventListener("input", this, true);
|
||||
browser.removeEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
browser.messageManager.removeMessageListener("SessionStore:pageshow", this);
|
||||
|
||||
delete browser.__SS_data;
|
||||
delete browser.__SS_tabStillLoading;
|
||||
delete browser.__SS_formDataSaved;
|
||||
@ -1289,17 +1310,14 @@ let SessionStoreInternal = {
|
||||
* Window reference
|
||||
* @param aBrowser
|
||||
* Browser reference
|
||||
* @param aEvent
|
||||
* Event obj
|
||||
*/
|
||||
onTabLoad: function ssi_onTabLoad(aWindow, aBrowser, aEvent) {
|
||||
onTabLoad: function ssi_onTabLoad(aWindow, aBrowser) {
|
||||
// react on "load" and solitary "pageshow" events (the first "pageshow"
|
||||
// following "load" is too late for deleting the data caches)
|
||||
// It's possible to get a load event after calling stop on a browser (when
|
||||
// overwriting tabs). We want to return early if the tab hasn't been restored yet.
|
||||
if ((aEvent.type != "load" && !aEvent.persisted) ||
|
||||
(aBrowser.__SS_restoreState &&
|
||||
aBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)) {
|
||||
if (aBrowser.__SS_restoreState &&
|
||||
aBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_form_restore_events_sample.html \
|
||||
browser_formdata_format.js \
|
||||
browser_formdata_format_sample.html \
|
||||
browser_pageshow.js \
|
||||
browser_248970_b_perwindowpb.js \
|
||||
browser_248970_b_sample.html \
|
||||
browser_339445.js \
|
||||
|
@ -88,11 +88,11 @@ function test_2() {
|
||||
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 1,
|
||||
"sessionstore state: 1 windows in data being writted to disk");
|
||||
"sessionstore state: 1 windows in data being written to disk");
|
||||
is (state.selectedWindow, 1,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
is(state._closedWindows.length, 0,
|
||||
"sessionstore state: no closed windows in data being writted to disk");
|
||||
"sessionstore state: no closed windows in data being written to disk");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
@ -114,20 +114,25 @@ function test_3() {
|
||||
is(curState.selectedWindow, 4, "Last window opened is the one selected");
|
||||
|
||||
waitForWindowClose(normalWindow, function() {
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 2,
|
||||
"sessionstore state: 2 windows in data being writted to disk");
|
||||
is(state.selectedWindow, 2,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
state.windows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Saved window is not private");
|
||||
// Load another tab before checking the written state so that
|
||||
// the list of restoring windows gets cleared. Otherwise the
|
||||
// window we just closed would be marked as not closed.
|
||||
waitForTabLoad(aWindow, "http://www.example.com/", function() {
|
||||
forceWriteState(function(state) {
|
||||
is(state.windows.length, 2,
|
||||
"sessionstore state: 2 windows in data being written to disk");
|
||||
is(state.selectedWindow, 2,
|
||||
"Selected window is updated to match one of the saved windows");
|
||||
state.windows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Saved window is not private");
|
||||
});
|
||||
is(state._closedWindows.length, 1,
|
||||
"sessionstore state: 1 closed window in data being written to disk");
|
||||
state._closedWindows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Closed window is not private");
|
||||
});
|
||||
runNextTest();
|
||||
});
|
||||
is(state._closedWindows.length, 1,
|
||||
"sessionstore state: 1 closed window in data being writted to disk");
|
||||
state._closedWindows.forEach(function(win) {
|
||||
is(!win.isPrivate, true, "Closed window is not private");
|
||||
});
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -178,7 +183,7 @@ function testOnWindow(aIsPrivate, aCallback) {
|
||||
function waitForTabLoad(aWin, aURL, aCallback) {
|
||||
aWin.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
aWin.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
aCallback();
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
aWin.gBrowser.selectedBrowser.loadURI(aURL);
|
||||
}
|
||||
|
84
browser/components/sessionstore/test/browser_pageshow.js
Normal file
84
browser/components/sessionstore/test/browser_pageshow.js
Normal file
@ -0,0 +1,84 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
TestRunner.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test ensures that loading a page from bfcache (by going back or forward
|
||||
* in history) marks the window as dirty and causes data about the tab that
|
||||
* changed to be re-collected.
|
||||
*
|
||||
* We will do this by creating a tab with two history entries and going back
|
||||
* to the first. When we now request the current browser state from the
|
||||
* session store service the first history entry must be selected.
|
||||
*/
|
||||
|
||||
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 two history entries.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
yield loadURI("about:robots");
|
||||
yield loadURI("about:mozilla");
|
||||
|
||||
// All windows currently marked as dirty will be written to disk
|
||||
// and thus marked clean afterwards.
|
||||
yield forceWriteState();
|
||||
|
||||
// Go back to 'about:robots' - which is loaded from the bfcache and thus
|
||||
// will not fire a 'load' event but a 'pageshow' event with persisted=true.
|
||||
waitForPageShow();
|
||||
yield gBrowser.selectedBrowser.goBack();
|
||||
is(tab.linkedBrowser.currentURI.spec, "about:robots", "url is about:robots");
|
||||
|
||||
// If by receiving the 'pageshow' event the first window has correctly
|
||||
// been marked as dirty, getBrowserState() should return the tab we created
|
||||
// with the right history entry (about:robots) selected.
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
is(state.windows[0].tabs[1].index, 1, "first history entry is selected");
|
||||
|
||||
// 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 loadURI(aURI) {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
waitForLoad(browser);
|
||||
browser.loadURI(aURI);
|
||||
}
|
||||
|
||||
function waitForLoad(aElement) {
|
||||
aElement.addEventListener("load", function onLoad() {
|
||||
aElement.removeEventListener("load", onLoad, true);
|
||||
executeSoon(next);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function waitForPageShow() {
|
||||
let mm = gBrowser.selectedBrowser.messageManager;
|
||||
|
||||
mm.addMessageListener("SessionStore:pageshow", function onPageShow() {
|
||||
mm.removeMessageListener("SessionStore:pageshow", onPageShow);
|
||||
executeSoon(next);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user