Bug 1110602 - Don't remove tour tabs from originTabs when switching tabs so they can continue to get notifications. r=Unfocused

--HG--
extra : rebase_source : efc2d7b81fe1df31192bef3360846e9508bcbcc3
This commit is contained in:
Matthew Noorenberghe 2015-01-21 13:21:41 -08:00
parent c67bbb5241
commit 48c093338b
6 changed files with 137 additions and 77 deletions

View File

@ -348,8 +348,8 @@ let gFxAccounts = {
// An entryPoint param is used for server-side metrics. If the current tab
// is UITour, assume that it initiated the call to this method and override
// the entryPoint accordingly.
if (UITour.originTabs.get(window) &&
UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
if (UITour.tourBrowsersByWindow.get(window) &&
UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
urlParams.entryPoint = "uitour";
}
let params = new URLSearchParams();

View File

@ -305,7 +305,8 @@ let gSyncUI = {
this.openPrefs();
} else {
// If the user is also in an uitour, set the entrypoint to `uitour`
if (UITour.originTabs.get(window) && UITour.originTabs.get(window).has(gBrowser.selectedTab)) {
if (UITour.tourBrowsersByWindow.get(window) &&
UITour.tourBrowsersByWindow.get(window).has(gBrowser.selectedBrowser)) {
entryPoint = "uitour";
}
switchToTabHavingURI("about:accounts?entrypoint=" + entryPoint, true, {

View File

@ -22,8 +22,8 @@ function openAboutAccountsFromMenuPanel(entryPoint) {
yield PanelUI.show();
if (entryPoint == "uitour") {
UITour.originTabs.set(window, new Set());
UITour.originTabs.get(window).add(gBrowser.selectedTab);
UITour.tourBrowsersByWindow.set(window, new Set());
UITour.tourBrowsersByWindow.get(window).add(gBrowser.selectedBrowser);
}
let syncButton = document.getElementById("sync-button");
@ -65,7 +65,7 @@ function asyncCleanup() {
// restore the tabs
gBrowser.addTab(initialLocation);
gBrowser.removeTab(newTab);
UITour.originTabs.delete(window);
UITour.tourBrowsersByWindow.delete(window);
}
add_task(() => openAboutAccountsFromMenuPanel("syncbutton"));

View File

@ -59,10 +59,9 @@ XPCOMUtils.defineLazyGetter(this, "log", () => {
this.UITour = {
url: null,
seenPageIDs: null,
pageIDSourceTabs: new WeakMap(),
pageIDSourceWindows: new WeakMap(),
/* Map from browser windows to a set of tabs in which a tour is open */
originTabs: new WeakMap(),
pageIDSourceBrowsers: new WeakMap(),
/* Map from browser chrome windows to a Set of <browser>s in which a tour is open (both visible and hidden) */
tourBrowsersByWindow: new WeakMap(),
urlbarCapture: new WeakMap(),
appMenuOpenForAnnotation: new Set(),
availableTargetsCache: new WeakMap(),
@ -385,12 +384,7 @@ this.UITour = {
}
this.addSeenPageID(data.pageID);
// Store tabs and windows separately so we don't need to loop over all
// tabs when a window is closed.
this.pageIDSourceTabs.set(tab, data.pageID);
this.pageIDSourceWindows.set(window, data.pageID);
this.pageIDSourceBrowsers.set(browser, data.pageID);
this.setTelemetryBucket(data.pageID);
break;
@ -638,25 +632,30 @@ this.UITour = {
}
}
if (!window.gMultiProcessBrowser) { // Non-e10s. See bug 1089000.
if (!this.originTabs.has(window)) {
this.originTabs.set(window, new Set());
}
this.originTabs.get(window).add(tab);
tab.addEventListener("TabClose", this);
tab.addEventListener("TabBecomingWindow", this);
window.addEventListener("SSWindowClosing", this);
if (!this.tourBrowsersByWindow.has(window)) {
this.tourBrowsersByWindow.set(window, new Set());
}
this.tourBrowsersByWindow.get(window).add(browser);
// We don't have a tab if it's being detached or we're in a <browser> without a tab.
if (tab) {
tab.addEventListener("TabClose", this);
if (!window.gMultiProcessBrowser) {
tab.addEventListener("TabBecomingWindow", this);
}
}
window.addEventListener("SSWindowClosing", this);
return true;
},
handleEvent: function(aEvent) {
log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
switch (aEvent.type) {
case "pagehide": {
let window = this.getChromeWindow(aEvent.target);
this.teardownTour(window);
this.teardownTourForWindow(window);
break;
}
@ -665,42 +664,30 @@ this.UITour = {
// Fall through
case "TabClose": {
let tab = aEvent.target;
if (this.pageIDSourceTabs.has(tab)) {
let pageID = this.pageIDSourceTabs.get(tab);
// Delete this from the window cache, so if the window is closed we
// don't expire this page ID twice.
let window = tab.ownerDocument.defaultView;
if (this.pageIDSourceWindows.get(window) == pageID)
this.pageIDSourceWindows.delete(window);
this.setExpiringTelemetryBucket(pageID, "closed");
}
let window = tab.ownerDocument.defaultView;
this.teardownTour(window);
this.teardownTourForBrowser(window, tab.linkedBrowser, true);
break;
}
case "TabSelect": {
let window = aEvent.target.ownerDocument.defaultView;
if (aEvent.detail && aEvent.detail.previousTab) {
let previousTab = aEvent.detail.previousTab;
if (this.pageIDSourceTabs.has(previousTab)) {
let pageID = this.pageIDSourceTabs.get(previousTab);
this.setExpiringTelemetryBucket(pageID, "inactive");
let openTourWindows = this.tourBrowsersByWindow.get(window);
if (openTourWindows.has(previousTab.linkedBrowser)) {
this.teardownTourForBrowser(window, previousTab.linkedBrowser, false);
}
}
let window = aEvent.target.ownerDocument.defaultView;
let pendingDoc;
if (this._detachingTab && this._pendingDoc && (pendingDoc = this._pendingDoc.get())) {
let selectedTab = window.gBrowser.selectedTab;
if (selectedTab.linkedBrowser.contentDocument == pendingDoc) {
if (!this.originTabs.get(window)) {
this.originTabs.set(window, new Set());
if (!this.tourBrowsersByWindow.get(window)) {
this.tourBrowsersByWindow.set(window, new Set());
}
this.originTabs.get(window).add(selectedTab);
this.tourBrowsersByWindow.get(window).add(selectedTab.linkedBrowser);
this.pendingDoc = null;
this._detachingTab = false;
while (this._queuedEvents.length) {
@ -714,18 +701,12 @@ this.UITour = {
}
}
this.teardownTour(window);
break;
}
case "SSWindowClosing": {
let window = aEvent.target;
if (this.pageIDSourceWindows.has(window)) {
let pageID = this.pageIDSourceWindows.get(window);
this.setExpiringTelemetryBucket(pageID, "closed");
}
this.teardownTour(window, true);
this.teardownTourForWindow(window);
break;
}
@ -760,29 +741,36 @@ this.UITour = {
};
},
teardownTour: function(aWindow, aWindowClosing = false) {
log.debug("teardownTour: aWindowClosing = " + aWindowClosing);
aWindow.gBrowser.tabContainer.removeEventListener("TabSelect", this);
aWindow.removeEventListener("SSWindowClosing", this);
/**
* Tear down a tour from a tab e.g. upon switching/closing tabs.
*/
teardownTourForBrowser: function(aWindow, aBrowser, aTourPageClosing = false) {
log.debug("teardownTourForBrowser: aBrowser = ", aBrowser, aTourPageClosing);
let originTabs = this.originTabs.get(aWindow);
if (originTabs) {
for (let tab of originTabs) {
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) {
let tab = aWindow.gBrowser.getTabForBrowser(aBrowser);
if (tab) { // Handle standalone <browser>
tab.removeEventListener("TabClose", this);
tab.removeEventListener("TabBecomingWindow", this);
if (openTourBrowsers) {
openTourBrowsers.delete(aBrowser);
}
}
}
this.originTabs.delete(aWindow);
if (!aWindowClosing) {
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.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");
// Clean up panel listeners after we may have called hideMenu above.
// Clean up panel listeners after calling hideMenu above.
aWindow.PanelUI.panel.removeEventListener("popuphiding", this.hideAppMenuAnnotations);
aWindow.PanelUI.panel.removeEventListener("ViewShowing", this.hideAppMenuAnnotations);
aWindow.PanelUI.panel.removeEventListener("popuphidden", this.onPanelHidden);
@ -792,6 +780,35 @@ this.UITour = {
this.endUrlbarCapture(aWindow);
this.resetTheme();
// If there are no more tour tabs left in the window, teardown the tour for the whole window.
if (!openTourBrowsers || openTourBrowsers.size == 0) {
this.teardownTourForWindow(aWindow);
}
},
/**
* 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");
}
let tab = aWindow.gBrowser.getTabForBrowser(browser);
tab.removeEventListener("TabClose", this);
}
}
this.tourBrowsersByWindow.delete(aWindow);
},
getChromeWindow: function(aContentDocument) {
@ -1232,6 +1249,7 @@ this.UITour = {
},
showMenu: function(aWindow, aMenuName, aOpenCallback = null) {
log.debug("showMenu:", aMenuName);
function openMenuButton(aMenuBtn) {
if (!aMenuBtn || !aMenuBtn.boxObject || aMenuBtn.open) {
if (aOpenCallback)
@ -1296,6 +1314,7 @@ this.UITour = {
},
hideMenu: function(aWindow, aMenuName) {
log.debug("hideMenu:", aMenuName);
function closeMenuButton(aMenuBtn) {
if (aMenuBtn && aMenuBtn.boxObject)
aMenuBtn.boxObject.openMenu(false);
@ -1625,12 +1644,16 @@ this.UITour = {
if (window.closed)
continue;
let originTabs = this.originTabs.get(window);
if (!originTabs)
let openTourBrowsers = this.tourBrowsersByWindow.get(window);
if (!openTourBrowsers)
continue;
for (let tab of originTabs) {
let messageManager = tab.linkedBrowser.messageManager;
for (let browser of openTourBrowsers) {
let messageManager = browser.messageManager;
if (!messageManager) {
log.error("notify: Trying to notify a browser without a messageManager", browser);
continue;
}
let detail = {
event: eventName,
params: params,

View File

@ -68,8 +68,8 @@ let tests = [
let selectedTab = gContentWindow.gBrowser.selectedTab;
is(selectedTab.linkedBrowser && selectedTab.linkedBrowser.contentDocument, gContentDoc, "Document should be selected in new window");
ok(UITour.originTabs && UITour.originTabs.has(gContentWindow), "Window should be known");
ok(UITour.originTabs.get(gContentWindow).has(selectedTab), "Tab should be known");
ok(UITour.tourBrowsersByWindow && UITour.tourBrowsersByWindow.has(gContentWindow), "Window should be known");
ok(UITour.tourBrowsersByWindow.get(gContentWindow).has(selectedTab.linkedBrowser), "Selected browser should be known");
let shownPromise = promisePanelShown(gContentWindow);
gContentAPI.showMenu("appMenu");

View File

@ -48,4 +48,40 @@ let tests = [
UITour.notify("test-event-3", {key: "something"});
});
},
];
function test_background_tab(done) {
function listener(event, params) {
is(event, "test-event-background-1", "Correct event name");
is(params, null, "No param object");
gContentAPI.observe(null);
gBrowser.removeCurrentTab();
done();
}
gContentAPI.observe(listener, () => {
gBrowser.selectedTab = gBrowser.addTab("about:blank");
isnot(gBrowser.selectedTab, gTestTab, "Make sure the selected tab changed");
UITour.notify("test-event-background-1");
});
},
// Make sure the tab isn't torn down when switching back to the tour one.
function test_background_then_foreground_tab(done) {
let blankTab = null;
function listener(event, params) {
is(event, "test-event-4", "Correct event name");
is(params, null, "No param object");
gContentAPI.observe(null);
gBrowser.removeTab(blankTab);
done();
}
gContentAPI.observe(listener, () => {
blankTab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
isnot(gBrowser.selectedTab, gTestTab, "Make sure the selected tab changed");
gBrowser.selectedTab = gTestTab;
is(gBrowser.selectedTab, gTestTab, "Switch back to the test tab");
UITour.notify("test-event-4");
});
},
];