--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -359,17 +359,23 @@ this.UITour = {
let originalUrl = ReaderMode.getOriginalUrl(aLocation);
if (this._readerViewTriggerRegEx.test(originalUrl)) {
this.startSubTour("readinglist");
}
},
onPageEvent: function(aMessage, aEvent) {
let browser = aMessage.target;
- let window = browser.ownerDocument.defaultView;
+ let window = browser.docShell
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+
+ // TODO: test with heartbeat (using windowless browser)
// Does the window have tabs? We need to make sure since windowless browsers do
// not have tabs.
if (!window.gBrowser) {
// When using windowless browsers we don't have a valid |window|. If that's the case,
// use the most recent window as a target for UITour functions (see Bug 1111022).
window = Services.wm.getMostRecentWindow("navigator:browser");
}
@@ -730,58 +736,68 @@ this.UITour = {
}
this.initForBrowser(browser, window);
return true;
},
initForBrowser(aBrowser, window) {
- let gBrowser = window.gBrowser;
-
- if (gBrowser) {
- gBrowser.tabContainer.addEventListener("TabSelect", this);
- }
+ aBrowser.addEventListener("visibilitychange", this.onVisibilityChange);
if (!this.tourBrowsersByWindow.has(window)) {
this.tourBrowsersByWindow.set(window, new Set());
}
this.tourBrowsersByWindow.get(window).add(aBrowser);
Services.obs.addObserver(this, "message-manager-close", false);
window.addEventListener("SSWindowClosing", this);
},
handleEvent: function(aEvent) {
log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
switch (aEvent.type) {
- case "TabSelect": {
- let window = aEvent.target.ownerDocument.defaultView;
-
- // Teardown the browser of the tab we just switched away from.
- if (aEvent.detail && aEvent.detail.previousTab) {
- let previousTab = aEvent.detail.previousTab;
- let openTourWindows = this.tourBrowsersByWindow.get(window);
- if (openTourWindows.has(previousTab.linkedBrowser)) {
- this.teardownTourForBrowser(window, previousTab.linkedBrowser, false);
- }
- }
-
- break;
- }
-
case "SSWindowClosing": {
let window = aEvent.target;
this.teardownTourForWindow(window);
break;
}
}
},
+ /**
+ * Teardown the tour for a browser when it is no longer visible
+ * (e.g. switching tabs, minimizing the window, or removing the browser).
+ *
+ * @param {Event} aEvent - visibilitychange event object
+ */
+ onVisibilityChange(aEvent) {
+ if (aEvent.target.visibilityState == "visible") {
+ return;
+ }
+
+ log.debug("visibilitychange:", aEvent);
+ // TODO: test with heartbeat (using windowless browser) making sure it never gets visibilitychange even on minimize
+
+ let browser = this;
+ let window = browser.docShell
+ .QueryInterface(Ci.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+
+ // Teardown the browser that just got hidden
+ let openTourWindows = UITour.tourBrowsersByWindow.get(window);
+ if (openTourWindows.has(browser)) {
+ let closing = aEvent.target.visibilityState == "unloaded";
+ UITour.teardownTourForBrowser(window, browser, closing);
+ }
+ },
+
observe: function(aSubject, aTopic, aData) {
log.debug("observe: aTopic =", aTopic);
switch (aTopic) {
// The browser message manager is disconnected when the <browser> is
// destroyed and we want to teardown at that point.
case "message-manager-close": {
let winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
@@ -884,16 +900,17 @@ this.UITour = {
if (this.pageIDSourceBrowsers.has(aBrowser)) {
let pageID = this.pageIDSourceBrowsers.get(aBrowser);
this.setExpiringTelemetryBucket(pageID, aTourPageClosing ? "closed" : "inactive");
}
let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
if (aTourPageClosing && openTourBrowsers) {
openTourBrowsers.delete(aBrowser);
+ aBrowser.removeEventListener("visibilitychange", this.onVisibilityChange);
}
this.hideHighlight(aWindow);
this.hideInfo(aWindow);
// Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
this.hideMenu(aWindow, "appMenu");
this.hideMenu(aWindow, "loop");
this.hideMenu(aWindow, "controlCenter");
@@ -917,17 +934,16 @@ this.UITour = {
}
},
/**
* Tear down all tours for a ChromeWindow.
*/
teardownTourForWindow: function(aWindow) {
log.debug("teardownTourForWindow");
- aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
aWindow.removeEventListener("SSWindowClosing", this);
let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
if (openTourBrowsers) {
for (let browser of openTourBrowsers) {
if (this.pageIDSourceBrowsers.has(browser)) {
let pageID = this.pageIDSourceBrowsers.get(browser);
this.setExpiringTelemetryBucket(pageID, "closed");