Bug 970321 - Australis' UITour: make menu panel not break if tour tab is opened in new window, r=Unfocused, a=sylvestre

This commit is contained in:
Gijs Kruitbosch 2014-02-20 22:42:33 +00:00
parent d36b49734f
commit 1293252519
6 changed files with 155 additions and 6 deletions

View file

@ -2492,6 +2492,15 @@
if (this.tabs.length == 1)
return null;
let event = new CustomEvent("TabBecomingWindow", {
bubbles: true,
cancelable: true
});
aTab.dispatchEvent(event);
if (event.defaultPrevented) {
return null;
}
var options = "chrome,dialog=no,all";
for (var name in aOptions)
options += "," + name + "=" + aOptions[name];

View file

@ -33,6 +33,7 @@ const PanelUI = {
};
},
_initialized: false,
init: function() {
for (let [k, v] of Iterator(this.kElements)) {
// Need to do fresh let-bindings per iteration
@ -46,6 +47,7 @@ const PanelUI = {
this.menuButton.addEventListener("mousedown", this);
this.menuButton.addEventListener("keypress", this);
this._initialized = true;
},
_eventListenersAdded: false,
@ -201,6 +203,18 @@ const PanelUI = {
return this._readyPromise;
}
this._readyPromise = Task.spawn(function() {
if (!this._initialized) {
let delayedStartupDeferred = Promise.defer();
let delayedStartupObserver = (aSubject, aTopic, aData) => {
if (aSubject == window) {
Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished");
delayedStartupDeferred.resolve();
}
};
Services.obs.addObserver(delayedStartupObserver, "browser-delayed-startup-finished", false);
yield delayedStartupDeferred.promise;
}
this.contents.setAttributeNS("http://www.w3.org/XML/1998/namespace", "lang",
getLocale());
if (!this._scrollWidth) {

View file

@ -42,11 +42,17 @@ this.UITour = {
seenPageIDs: new Set(),
pageIDSourceTabs: new WeakMap(),
pageIDSourceWindows: new WeakMap(),
/* Map from browser windows to a set of tabs in which a tour is open */
originTabs: new WeakMap(),
/* Map from browser windows to a set of pinned tabs opened by (a) tour(s) */
pinnedTabs: new WeakMap(),
urlbarCapture: new WeakMap(),
appMenuOpenForAnnotation: new Set(),
_detachingTab: false,
_queuedEvents: [],
_pendingDoc: null,
highlightEffects: ["random", "wobble", "zoom", "color"],
targets: new Map([
["accountStatus", {
@ -138,7 +144,20 @@ this.UITour = {
return false;
let window = this.getChromeWindow(contentDocument);
// Do this before bailing if there's no tab, so later we can pick up the pieces:
window.gBrowser.tabContainer.addEventListener("TabSelect", this);
let tab = window.gBrowser._getTabForContentWindow(contentDocument.defaultView);
if (!tab) {
// This should only happen while detaching a tab:
if (this._detachingTab) {
this._queuedEvents.push(aEvent);
this._pendingDoc = Cu.getWeakReference(contentDocument);
return;
}
Cu.reportError("Discarding tabless UITour event (" + action + ") while not detaching a tab." +
"This shouldn't happen!");
return;
}
switch (action) {
case "registerPageID": {
@ -299,10 +318,10 @@ this.UITour = {
if (!this.originTabs.has(window))
this.originTabs.set(window, new Set());
this.originTabs.get(window).add(tab);
this.originTabs.get(window).add(tab);
tab.addEventListener("TabClose", this);
window.gBrowser.tabContainer.addEventListener("TabSelect", this);
tab.addEventListener("TabBecomingWindow", this);
window.addEventListener("SSWindowClosing", this);
return true;
@ -316,6 +335,9 @@ this.UITour = {
break;
}
case "TabBecomingWindow":
this._detachingTab = true;
// Fall through
case "TabClose": {
let tab = aEvent.target;
if (this.pageIDSourceTabs.has(tab)) {
@ -346,13 +368,34 @@ this.UITour = {
}
let window = aEvent.target.ownerDocument.defaultView;
let selectedTab = window.gBrowser.selectedTab;
let pinnedTab = this.pinnedTabs.get(window);
if (pinnedTab && pinnedTab.tab == window.gBrowser.selectedTab)
if (pinnedTab && pinnedTab.tab == selectedTab)
break;
let originTabs = this.originTabs.get(window);
if (originTabs && originTabs.has(window.gBrowser.selectedTab))
if (originTabs && originTabs.has(selectedTab))
break;
let pendingDoc;
if (this._detachingTab && this._pendingDoc && (pendingDoc = this._pendingDoc.get())) {
if (selectedTab.linkedBrowser.contentDocument == pendingDoc) {
if (!this.originTabs.get(window)) {
this.originTabs.set(window, new Set());
}
this.originTabs.get(window).add(selectedTab);
this.pendingDoc = null;
this._detachingTab = false;
while (this._queuedEvents.length) {
try {
this.onPageEvent(this._queuedEvents.shift());
} catch (ex) {
Cu.reportError(ex);
}
}
break;
}
}
this.teardownTour(window);
break;
}
@ -413,8 +456,10 @@ this.UITour = {
let originTabs = this.originTabs.get(aWindow);
if (originTabs) {
for (let tab of originTabs)
for (let tab of originTabs) {
tab.removeEventListener("TabClose", this);
tab.removeEventListener("TabBecomingWindow", this);
}
}
this.originTabs.delete(aWindow);

View file

@ -12,6 +12,7 @@ skip-if = os == "linux" # Intermittent failures, bug 951965
[browser_UITour2.js]
[browser_UITour3.js]
[browser_UITour_panel_close_annotation.js]
[browser_UITour_detach_tab.js]
[browser_UITour_registerPageID.js]
[browser_UITour_sync.js]
[browser_taskbar_preview.js]

View file

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that annotations disappear when their target is hidden.
*/
"use strict";
let gTestTab;
let gContentAPI;
let gContentWindow;
let gContentDoc;
let highlight = document.getElementById("UITourHighlight");
let tooltip = document.getElementById("UITourTooltip");
Components.utils.import("resource:///modules/UITour.jsm");
function test() {
registerCleanupFunction(function() {
gContentDoc = null;
});
UITourTest();
}
let tests = [
function test_move_tab_to_new_window(done) {
let gOpenedWindow;
let onVisibilityChange = (aEvent) => {
if (!document.hidden && window != UITour.getChromeWindow(aEvent.target)) {
gContentAPI.showHighlight("appMenu");
}
};
let onDOMWindowDestroyed = (aWindow, aTopic, aData) => {
if (gOpenedWindow && aWindow == gOpenedWindow) {
Services.obs.removeObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
done();
}
};
let onBrowserDelayedStartup = (aWindow, aTopic, aData) => {
gOpenedWindow = aWindow;
Services.obs.removeObserver(onBrowserDelayedStartup, "browser-delayed-startup-finished");
try {
let newWindowHighlight = gOpenedWindow.document.getElementById("UITourHighlight");
let selectedTab = aWindow.gBrowser.selectedTab;
is(selectedTab.linkedBrowser && selectedTab.linkedBrowser.contentDocument, gContentDoc, "Document should be selected in new window");
ok(UITour.originTabs && UITour.originTabs.has(aWindow), "Window should be known");
ok(UITour.originTabs.get(aWindow).has(selectedTab), "Tab should be known");
waitForElementToBeVisible(newWindowHighlight, function checkHighlightIsThere() {
gContentAPI.showMenu("appMenu");
isnot(aWindow.PanelUI.panel.state, "closed", "Panel should be open");
ok(aWindow.PanelUI.contents.children.length > 0, "Panel contents should have children");
gContentAPI.hideHighlight();
gContentAPI.hideMenu("appMenu");
gTestTab = null;
aWindow.close();
}, "Highlight should be shown in new window.");
} catch (ex) {
Cu.reportError(ex);
ok(false, "An error occurred running UITour tab detach test.");
} finally {
gContentDoc.removeEventListener("visibilitychange", onVisibilityChange, false);
Services.obs.addObserver(onDOMWindowDestroyed, "dom-window-destroyed", false);
}
};
Services.obs.addObserver(onBrowserDelayedStartup, "browser-delayed-startup-finished", false);
// NB: we're using this rather than gContentWindow.document because the latter wouldn't
// have an XRayWrapper, and we need to compare this to the doc we get using this method
// later on...
gContentDoc = gBrowser.selectedTab.linkedBrowser.contentDocument;
gContentDoc.addEventListener("visibilitychange", onVisibilityChange, false);
gContentAPI.showHighlight("appMenu");
waitForElementToBeVisible(highlight, function checkForInitialHighlight() {
gBrowser.replaceTabWithWindow(gBrowser.selectedTab);
});
},
];

View file

@ -78,7 +78,7 @@ function is_element_hidden(element, msg) {
}
function loadUITourTestPage(callback, host = "https://example.com/") {
if (gTestTab)
if (gTestTab)
gBrowser.removeTab(gTestTab);
let url = getRootDirectory(gTestPath) + "uitour.html";