Bug 742098 - refactor observe() into a set of distinct methods [r=zpao]

This commit is contained in:
Max Li 2012-04-11 12:52:48 -07:00
parent d6d86609db
commit be2df2f0e7

View File

@ -497,265 +497,43 @@ SessionStoreService.prototype = {
* Handle notifications
*/
observe: function sss_observe(aSubject, aTopic, aData) {
// for event listeners
var _this = this;
switch (aTopic) {
case "domwindowopened": // catch new windows
aSubject.addEventListener("load", function(aEvent) {
aEvent.currentTarget.removeEventListener("load", arguments.callee, false);
_this.onLoad(aEvent.currentTarget);
}, false);
break;
case "domwindowclosed": // catch closed windows
this.onClose(aSubject);
break;
case "quit-application-requested":
// get a current snapshot of all windows
this._forEachBrowserWindow(function(aWindow) {
this._collectWindowData(aWindow);
});
// we must cache this because _getMostRecentBrowserWindow will always
// return null by the time quit-application occurs
var activeWindow = this._getMostRecentBrowserWindow();
if (activeWindow)
this.activeWindowSSiCache = activeWindow.__SSi || "";
this._dirtyWindows = [];
break;
case "quit-application-granted":
// freeze the data at what we've got (ignoring closing windows)
this._loadState = STATE_QUITTING;
break;
case "browser-lastwindow-close-granted":
// last browser window is quitting.
// remember to restore the last window when another browser window is opened
// do not account for pref(resume_session_once) at this point, as it might be
// set by another observer getting this notice after us
this._restoreLastWindow = true;
break;
case "quit-application":
if (aData == "restart") {
this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
// The browser:purge-session-history notification fires after the
// quit-application notification so unregister the
// browser:purge-session-history notification to prevent clearing
// session data on disk on a restart. It is also unnecessary to
// perform any other sanitization processing on a restart as the
// browser is about to exit anyway.
Services.obs.removeObserver(this, "browser:purge-session-history");
}
else if (this._resume_session_once_on_shutdown != null) {
// if the sessionstore.resume_session_once preference was changed by
// saveState because crash recovery is disabled then restore the
// preference back to the value it was prior to that. This will prevent
// SessionStore from always restoring the session when crash recovery is
// disabled.
this._prefBranch.setBoolPref("sessionstore.resume_session_once",
this._resume_session_once_on_shutdown);
}
if (aData != "restart") {
// Throw away the previous session on shutdown
this._lastSessionState = null;
}
this._loadState = STATE_QUITTING; // just to be sure
this._uninit();
break;
case "browser:purge-session-history": // catch sanitization
this._clearDisk();
// If the browser is shutting down, simply return after clearing the
// session data on disk as this notification fires after the
// quit-application notification so the browser is about to exit.
if (this._loadState == STATE_QUITTING)
return;
this._lastSessionState = null;
let openWindows = {};
this._forEachBrowserWindow(function(aWindow) {
Array.forEach(aWindow.gBrowser.tabs, function(aTab) {
delete aTab.linkedBrowser.__SS_data;
delete aTab.linkedBrowser.__SS_tabStillLoading;
delete aTab.linkedBrowser.__SS_formDataSaved;
delete aTab.linkedBrowser.__SS_hostSchemeData;
if (aTab.linkedBrowser.__SS_restoreState)
this._resetTabRestoringState(aTab);
});
openWindows[aWindow.__SSi] = true;
});
// also clear all data about closed tabs and windows
for (let ix in this._windows) {
if (ix in openWindows) {
this._windows[ix]._closedTabs = [];
}
else {
delete this._windows[ix];
delete this._internalWindows[ix];
}
}
// also clear all data about closed windows
this._closedWindows = [];
// give the tabbrowsers a chance to clear their histories first
var win = this._getMostRecentBrowserWindow();
if (win)
win.setTimeout(function() { _this.saveState(true); }, 0);
else if (this._loadState == STATE_RUNNING)
this.saveState(true);
// Delete the private browsing backed up state, if any
if ("_stateBackup" in this)
delete this._stateBackup;
this._clearRestoringWindows();
break;
case "browser:purge-domain-data":
// does a session history entry contain a url for the given domain?
function containsDomain(aEntry) {
try {
if (this._getURIFromString(aEntry.url).host.hasRootDomain(aData))
return true;
}
catch (ex) { /* url had no host at all */ }
return aEntry.children && aEntry.children.some(containsDomain, this);
}
// remove all closed tabs containing a reference to the given domain
for (let ix in this._windows) {
let closedTabs = this._windows[ix]._closedTabs;
for (let i = closedTabs.length - 1; i >= 0; i--) {
if (closedTabs[i].state.entries.some(containsDomain, this))
closedTabs.splice(i, 1);
}
}
// remove all open & closed tabs containing a reference to the given
// domain in closed windows
for (let ix = this._closedWindows.length - 1; ix >= 0; ix--) {
let closedTabs = this._closedWindows[ix]._closedTabs;
let openTabs = this._closedWindows[ix].tabs;
let openTabCount = openTabs.length;
for (let i = closedTabs.length - 1; i >= 0; i--)
if (closedTabs[i].state.entries.some(containsDomain, this))
closedTabs.splice(i, 1);
for (let j = openTabs.length - 1; j >= 0; j--) {
if (openTabs[j].entries.some(containsDomain, this)) {
openTabs.splice(j, 1);
if (this._closedWindows[ix].selected > j)
this._closedWindows[ix].selected--;
}
}
if (openTabs.length == 0) {
this._closedWindows.splice(ix, 1);
}
else if (openTabs.length != openTabCount) {
// Adjust the window's title if we removed an open tab
let selectedTab = openTabs[this._closedWindows[ix].selected - 1];
// some duplication from restoreHistory - make sure we get the correct title
let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
if (activeIndex >= selectedTab.entries.length)
activeIndex = selectedTab.entries.length - 1;
this._closedWindows[ix].title = selectedTab.entries[activeIndex].title;
}
}
if (this._loadState == STATE_RUNNING)
this.saveState(true);
this._clearRestoringWindows();
break;
case "nsPref:changed": // catch pref changes
switch (aData) {
// if the user decreases the max number of closed tabs they want
// preserved update our internal states to match that max
case "sessionstore.max_tabs_undo":
this._max_tabs_undo = this._prefBranch.getIntPref("sessionstore.max_tabs_undo");
for (let ix in this._windows) {
this._windows[ix]._closedTabs.splice(this._max_tabs_undo, this._windows[ix]._closedTabs.length);
}
case "domwindowopened": // catch new windows
this.onOpen(aSubject);
break;
case "sessionstore.max_windows_undo":
this._max_windows_undo = this._prefBranch.getIntPref("sessionstore.max_windows_undo");
this._capClosedWindows();
case "domwindowclosed": // catch closed windows
this.onClose(aSubject);
break;
case "sessionstore.interval":
this._interval = this._prefBranch.getIntPref("sessionstore.interval");
// reset timer and save
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
}
this.saveStateDelayed(null, -1);
case "quit-application-requested":
this.onQuitApplicationRequested();
break;
case "sessionstore.resume_from_crash":
this._resume_from_crash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
// restore original resume_session_once preference if set in saveState
if (this._resume_session_once_on_shutdown != null) {
this._prefBranch.setBoolPref("sessionstore.resume_session_once",
this._resume_session_once_on_shutdown);
this._resume_session_once_on_shutdown = null;
}
// either create the file with crash recovery information or remove it
// (when _loadState is not STATE_RUNNING, that file is used for session resuming instead)
if (!this._resume_from_crash)
this._clearDisk();
this.saveState(true);
case "quit-application-granted":
this.onQuitApplicationGranted();
break;
case "sessionstore.restore_on_demand":
this._restoreOnDemand =
this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
case "browser-lastwindow-close-granted":
this.onLastWindowCloseGranted();
break;
case "sessionstore.restore_hidden_tabs":
this._restoreHiddenTabs =
this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
case "quit-application":
this.onQuitApplication(aData);
break;
case "sessionstore.restore_pinned_tabs_on_demand":
this._restorePinnedTabsOnDemand =
this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
case "browser:purge-session-history": // catch sanitization
this.onPurgeSessionHistory();
break;
}
break;
case "timer-callback": // timer call back for delayed saving
this._saveTimer = null;
this.saveState();
break;
case "private-browsing":
switch (aData) {
case "enter":
this._inPrivateBrowsing = true;
case "browser:purge-domain-data":
this.onPurgeDomainData(aData);
break;
case "exit":
aSubject.QueryInterface(Ci.nsISupportsPRBool);
let quitting = aSubject.data;
if (quitting) {
// save the backed up state with session set to stopped,
// otherwise resuming next time would look like a crash.
// Whether we restore the session upon resume will be determined by the
// usual startup prefs, so we will have the same behavior regardless of
// whether the browser was closed while in normal or private browsing mode.
if ("_stateBackup" in this) {
var oState = this._stateBackup;
oState.session = { state: STATE_STOPPED_STR };
this._saveStateObject(oState);
}
}
else
this._inPrivateBrowsing = false;
delete this._stateBackup;
case "nsPref:changed": // catch pref changes
this.onPrefChange(aData);
break;
case "timer-callback": // timer call back for delayed saving
this.onTimerCallback();
break;
case "private-browsing":
this.onPrivateBrowsing(aSubject, aData);
break;
case "private-browsing-change-granted":
this.onPrivateBrowsingChangeGranted(aData);
break;
}
this._clearRestoringWindows();
break;
case "private-browsing-change-granted":
if (aData == "enter") {
this.saveState(true);
// We stringify & parse the current state so that we have have an object
// that won't change. _getCurrentState returns an object with references
// to objects that can change (specifically this._windows[x]).
this._stateBackup = JSON.parse(this._toJSONString(this._getCurrentState(true)));
}
// Make sure _tabsToRestore is cleared. It will be repopulated when
// entering/exiting private browsing (by calls to setBrowserState).
this._resetRestoringState();
this._clearRestoringWindows();
break;
}
},
@ -956,6 +734,20 @@ SessionStoreService.prototype = {
tabbrowser.tabContainer.addEventListener(aEvent, this, true);
}, this);
},
/**
* On window open
* @param aWindow
* Window reference
*/
onOpen: function sss_onOpen(aWindow) {
var _this = this;
aWindow.addEventListener("load", function(aEvent) {
aEvent.currentTarget.removeEventListener("load", arguments.callee, false);
_this.onLoad(aEvent.currentTarget);
}, false);
return;
},
/**
* On window close...
@ -1048,6 +840,305 @@ SessionStoreService.prototype = {
delete aWindow.__SSi;
},
/**
* On quit application requested
*/
onQuitApplicationRequested: function sss_onQuitApplicationRequested() {
// get a current snapshot of all windows
this._forEachBrowserWindow(function(aWindow) {
this._collectWindowData(aWindow);
});
// we must cache this because _getMostRecentBrowserWindow will always
// return null by the time quit-application occurs
var activeWindow = this._getMostRecentBrowserWindow();
if (activeWindow)
this.activeWindowSSiCache = activeWindow.__SSi || "";
this._dirtyWindows = [];
},
/**
* On quit application granted
*/
onQuitApplicationGranted: function sss_onQuitApplicationGranted() {
// freeze the data at what we've got (ignoring closing windows)
this._loadState = STATE_QUITTING;
},
/**
* On last browser window close
*/
onLastWindowCloseGranted: function sss_onLastWindowCloseGranted() {
// last browser window is quitting.
// remember to restore the last window when another browser window is opened
// do not account for pref(resume_session_once) at this point, as it might be
// set by another observer getting this notice after us
this._restoreLastWindow = true;
},
/**
* On quitting application
* @param aData
* String type of quitting
*/
onQuitApplication: function sss_onQuitApplication(aData) {
if (aData == "restart") {
this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
// The browser:purge-session-history notification fires after the
// quit-application notification so unregister the
// browser:purge-session-history notification to prevent clearing
// session data on disk on a restart. It is also unnecessary to
// perform any other sanitization processing on a restart as the
// browser is about to exit anyway.
Services.obs.removeObserver(this, "browser:purge-session-history");
}
else if (this._resume_session_once_on_shutdown != null) {
// if the sessionstore.resume_session_once preference was changed by
// saveState because crash recovery is disabled then restore the
// preference back to the value it was prior to that. This will prevent
// SessionStore from always restoring the session when crash recovery is
// disabled.
this._prefBranch.setBoolPref("sessionstore.resume_session_once",
this._resume_session_once_on_shutdown);
}
if (aData != "restart") {
// Throw away the previous session on shutdown
this._lastSessionState = null;
}
this._loadState = STATE_QUITTING; // just to be sure
this._uninit();
},
/**
* On purge of session history
*/
onPurgeSessionHistory: function sss_onPurgeSessionHistory() {
var _this = this;
this._clearDisk();
// If the browser is shutting down, simply return after clearing the
// session data on disk as this notification fires after the
// quit-application notification so the browser is about to exit.
if (this._loadState == STATE_QUITTING)
return;
this._lastSessionState = null;
let openWindows = {};
this._forEachBrowserWindow(function(aWindow) {
Array.forEach(aWindow.gBrowser.tabs, function(aTab) {
delete aTab.linkedBrowser.__SS_data;
delete aTab.linkedBrowser.__SS_tabStillLoading;
delete aTab.linkedBrowser.__SS_formDataSaved;
delete aTab.linkedBrowser.__SS_hostSchemeData;
if (aTab.linkedBrowser.__SS_restoreState)
this._resetTabRestoringState(aTab);
});
openWindows[aWindow.__SSi] = true;
});
// also clear all data about closed tabs and windows
for (let ix in this._windows) {
if (ix in openWindows) {
this._windows[ix]._closedTabs = [];
}
else {
delete this._windows[ix];
delete this._internalWindows[ix];
}
}
// also clear all data about closed windows
this._closedWindows = [];
// give the tabbrowsers a chance to clear their histories first
var win = this._getMostRecentBrowserWindow();
if (win)
win.setTimeout(function() { _this.saveState(true); }, 0);
else if (this._loadState == STATE_RUNNING)
this.saveState(true);
// Delete the private browsing backed up state, if any
if ("_stateBackup" in this)
delete this._stateBackup;
this._clearRestoringWindows();
},
/**
* On purge of domain data
* @param aData
* String domain data
*/
onPurgeDomainData: function sss_onPurgeDomainData(aData) {
// does a session history entry contain a url for the given domain?
function containsDomain(aEntry) {
try {
if (this._getURIFromString(aEntry.url).host.hasRootDomain(aData))
return true;
}
catch (ex) { /* url had no host at all */ }
return aEntry.children && aEntry.children.some(containsDomain, this);
}
// remove all closed tabs containing a reference to the given domain
for (let ix in this._windows) {
let closedTabs = this._windows[ix]._closedTabs;
for (let i = closedTabs.length - 1; i >= 0; i--) {
if (closedTabs[i].state.entries.some(containsDomain, this))
closedTabs.splice(i, 1);
}
}
// remove all open & closed tabs containing a reference to the given
// domain in closed windows
for (let ix = this._closedWindows.length - 1; ix >= 0; ix--) {
let closedTabs = this._closedWindows[ix]._closedTabs;
let openTabs = this._closedWindows[ix].tabs;
let openTabCount = openTabs.length;
for (let i = closedTabs.length - 1; i >= 0; i--)
if (closedTabs[i].state.entries.some(containsDomain, this))
closedTabs.splice(i, 1);
for (let j = openTabs.length - 1; j >= 0; j--) {
if (openTabs[j].entries.some(containsDomain, this)) {
openTabs.splice(j, 1);
if (this._closedWindows[ix].selected > j)
this._closedWindows[ix].selected--;
}
}
if (openTabs.length == 0) {
this._closedWindows.splice(ix, 1);
}
else if (openTabs.length != openTabCount) {
// Adjust the window's title if we removed an open tab
let selectedTab = openTabs[this._closedWindows[ix].selected - 1];
// some duplication from restoreHistory - make sure we get the correct title
let activeIndex = (selectedTab.index || selectedTab.entries.length) - 1;
if (activeIndex >= selectedTab.entries.length)
activeIndex = selectedTab.entries.length - 1;
this._closedWindows[ix].title = selectedTab.entries[activeIndex].title;
}
}
if (this._loadState == STATE_RUNNING)
this.saveState(true);
this._clearRestoringWindows();
},
/**
* On preference change
* @param aData
* String preference changed
*/
onPrefChange: function sss_onPrefChange(aData) {
switch (aData) {
// if the user decreases the max number of closed tabs they want
// preserved update our internal states to match that max
case "sessionstore.max_tabs_undo":
this._max_tabs_undo = this._prefBranch.getIntPref("sessionstore.max_tabs_undo");
for (let ix in this._windows) {
this._windows[ix]._closedTabs.splice(this._max_tabs_undo, this._windows[ix]._closedTabs.length);
}
break;
case "sessionstore.max_windows_undo":
this._max_windows_undo = this._prefBranch.getIntPref("sessionstore.max_windows_undo");
this._capClosedWindows();
break;
case "sessionstore.interval":
this._interval = this._prefBranch.getIntPref("sessionstore.interval");
// reset timer and save
if (this._saveTimer) {
this._saveTimer.cancel();
this._saveTimer = null;
}
this.saveStateDelayed(null, -1);
break;
case "sessionstore.resume_from_crash":
this._resume_from_crash = this._prefBranch.getBoolPref("sessionstore.resume_from_crash");
// restore original resume_session_once preference if set in saveState
if (this._resume_session_once_on_shutdown != null) {
this._prefBranch.setBoolPref("sessionstore.resume_session_once",
this._resume_session_once_on_shutdown);
this._resume_session_once_on_shutdown = null;
}
// either create the file with crash recovery information or remove it
// (when _loadState is not STATE_RUNNING, that file is used for session resuming instead)
if (!this._resume_from_crash)
this._clearDisk();
this.saveState(true);
break;
case "sessionstore.restore_on_demand":
this._restoreOnDemand =
this._prefBranch.getBoolPref("sessionstore.restore_on_demand");
break;
case "sessionstore.restore_hidden_tabs":
this._restoreHiddenTabs =
this._prefBranch.getBoolPref("sessionstore.restore_hidden_tabs");
break;
case "sessionstore.restore_pinned_tabs_on_demand":
this._restorePinnedTabsOnDemand =
this._prefBranch.getBoolPref("sessionstore.restore_pinned_tabs_on_demand");
break;
}
},
/**
* On timer callback
*/
onTimerCallback: function sss_onTimerCallback() {
this._saveTimer = null;
this.saveState();
},
/**
* On private browsing
* @param aSubject
* Window reference
* @param aData
* String whether to enter or exit private browsing
*/
onPrivateBrowsing: function sss_onPrivateBrowsing(aSubject, aData) {
switch (aData) {
case "enter":
this._inPrivateBrowsing = true;
break;
case "exit":
aSubject.QueryInterface(Ci.nsISupportsPRBool);
let quitting = aSubject.data;
if (quitting) {
// save the backed up state with session set to stopped,
// otherwise resuming next time would look like a crash.
// Whether we restore the session upon resume will be determined by the
// usual startup prefs, so we will have the same behavior regardless of
// whether the browser was closed while in normal or private browsing mode.
if ("_stateBackup" in this) {
var oState = this._stateBackup;
oState.session = { state: STATE_STOPPED_STR };
this._saveStateObject(oState);
}
}
else
this._inPrivateBrowsing = false;
delete this._stateBackup;
break;
}
this._clearRestoringWindows();
},
/**
* On private browsing change granted
* @param aData
* String whether to enter or exit private browsing
*/
onPrivateBrowsingChangeGranted: function sss_onPrivateBrowsingChangeGranted(aData) {
if (aData == "enter") {
this.saveState(true);
// We stringify & parse the current state so that we have have an object
// that won't change. _getCurrentState returns an object with references
// to objects that can change (specifically this._windows[x]).
this._stateBackup = JSON.parse(this._toJSONString(this._getCurrentState(true)));
}
// Make sure _tabsToRestore is cleared. It will be repopulated when
// entering/exiting private browsing (by calls to setBrowserState).
this._resetRestoringState();
this._clearRestoringWindows();
},
/**
* set up listeners for a new tab
* @param aWindow