forked from mirrors/gecko-dev
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:
parent
d36b49734f
commit
1293252519
6 changed files with 155 additions and 6 deletions
|
|
@ -2492,6 +2492,15 @@
|
||||||
if (this.tabs.length == 1)
|
if (this.tabs.length == 1)
|
||||||
return null;
|
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";
|
var options = "chrome,dialog=no,all";
|
||||||
for (var name in aOptions)
|
for (var name in aOptions)
|
||||||
options += "," + name + "=" + aOptions[name];
|
options += "," + name + "=" + aOptions[name];
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ const PanelUI = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_initialized: false,
|
||||||
init: function() {
|
init: function() {
|
||||||
for (let [k, v] of Iterator(this.kElements)) {
|
for (let [k, v] of Iterator(this.kElements)) {
|
||||||
// Need to do fresh let-bindings per iteration
|
// Need to do fresh let-bindings per iteration
|
||||||
|
|
@ -46,6 +47,7 @@ const PanelUI = {
|
||||||
|
|
||||||
this.menuButton.addEventListener("mousedown", this);
|
this.menuButton.addEventListener("mousedown", this);
|
||||||
this.menuButton.addEventListener("keypress", this);
|
this.menuButton.addEventListener("keypress", this);
|
||||||
|
this._initialized = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_eventListenersAdded: false,
|
_eventListenersAdded: false,
|
||||||
|
|
@ -201,6 +203,18 @@ const PanelUI = {
|
||||||
return this._readyPromise;
|
return this._readyPromise;
|
||||||
}
|
}
|
||||||
this._readyPromise = Task.spawn(function() {
|
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",
|
this.contents.setAttributeNS("http://www.w3.org/XML/1998/namespace", "lang",
|
||||||
getLocale());
|
getLocale());
|
||||||
if (!this._scrollWidth) {
|
if (!this._scrollWidth) {
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,17 @@ this.UITour = {
|
||||||
seenPageIDs: new Set(),
|
seenPageIDs: new Set(),
|
||||||
pageIDSourceTabs: new WeakMap(),
|
pageIDSourceTabs: new WeakMap(),
|
||||||
pageIDSourceWindows: new WeakMap(),
|
pageIDSourceWindows: new WeakMap(),
|
||||||
|
/* Map from browser windows to a set of tabs in which a tour is open */
|
||||||
originTabs: new WeakMap(),
|
originTabs: new WeakMap(),
|
||||||
|
/* Map from browser windows to a set of pinned tabs opened by (a) tour(s) */
|
||||||
pinnedTabs: new WeakMap(),
|
pinnedTabs: new WeakMap(),
|
||||||
urlbarCapture: new WeakMap(),
|
urlbarCapture: new WeakMap(),
|
||||||
appMenuOpenForAnnotation: new Set(),
|
appMenuOpenForAnnotation: new Set(),
|
||||||
|
|
||||||
|
_detachingTab: false,
|
||||||
|
_queuedEvents: [],
|
||||||
|
_pendingDoc: null,
|
||||||
|
|
||||||
highlightEffects: ["random", "wobble", "zoom", "color"],
|
highlightEffects: ["random", "wobble", "zoom", "color"],
|
||||||
targets: new Map([
|
targets: new Map([
|
||||||
["accountStatus", {
|
["accountStatus", {
|
||||||
|
|
@ -138,7 +144,20 @@ this.UITour = {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let window = this.getChromeWindow(contentDocument);
|
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);
|
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) {
|
switch (action) {
|
||||||
case "registerPageID": {
|
case "registerPageID": {
|
||||||
|
|
@ -299,10 +318,10 @@ this.UITour = {
|
||||||
|
|
||||||
if (!this.originTabs.has(window))
|
if (!this.originTabs.has(window))
|
||||||
this.originTabs.set(window, new Set());
|
this.originTabs.set(window, new Set());
|
||||||
this.originTabs.get(window).add(tab);
|
|
||||||
|
|
||||||
|
this.originTabs.get(window).add(tab);
|
||||||
tab.addEventListener("TabClose", this);
|
tab.addEventListener("TabClose", this);
|
||||||
window.gBrowser.tabContainer.addEventListener("TabSelect", this);
|
tab.addEventListener("TabBecomingWindow", this);
|
||||||
window.addEventListener("SSWindowClosing", this);
|
window.addEventListener("SSWindowClosing", this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -316,6 +335,9 @@ this.UITour = {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "TabBecomingWindow":
|
||||||
|
this._detachingTab = true;
|
||||||
|
// Fall through
|
||||||
case "TabClose": {
|
case "TabClose": {
|
||||||
let tab = aEvent.target;
|
let tab = aEvent.target;
|
||||||
if (this.pageIDSourceTabs.has(tab)) {
|
if (this.pageIDSourceTabs.has(tab)) {
|
||||||
|
|
@ -346,13 +368,34 @@ this.UITour = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = aEvent.target.ownerDocument.defaultView;
|
let window = aEvent.target.ownerDocument.defaultView;
|
||||||
|
let selectedTab = window.gBrowser.selectedTab;
|
||||||
let pinnedTab = this.pinnedTabs.get(window);
|
let pinnedTab = this.pinnedTabs.get(window);
|
||||||
if (pinnedTab && pinnedTab.tab == window.gBrowser.selectedTab)
|
if (pinnedTab && pinnedTab.tab == selectedTab)
|
||||||
break;
|
break;
|
||||||
let originTabs = this.originTabs.get(window);
|
let originTabs = this.originTabs.get(window);
|
||||||
if (originTabs && originTabs.has(window.gBrowser.selectedTab))
|
if (originTabs && originTabs.has(selectedTab))
|
||||||
break;
|
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);
|
this.teardownTour(window);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -413,8 +456,10 @@ this.UITour = {
|
||||||
|
|
||||||
let originTabs = this.originTabs.get(aWindow);
|
let originTabs = this.originTabs.get(aWindow);
|
||||||
if (originTabs) {
|
if (originTabs) {
|
||||||
for (let tab of originTabs)
|
for (let tab of originTabs) {
|
||||||
tab.removeEventListener("TabClose", this);
|
tab.removeEventListener("TabClose", this);
|
||||||
|
tab.removeEventListener("TabBecomingWindow", this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.originTabs.delete(aWindow);
|
this.originTabs.delete(aWindow);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ skip-if = os == "linux" # Intermittent failures, bug 951965
|
||||||
[browser_UITour2.js]
|
[browser_UITour2.js]
|
||||||
[browser_UITour3.js]
|
[browser_UITour3.js]
|
||||||
[browser_UITour_panel_close_annotation.js]
|
[browser_UITour_panel_close_annotation.js]
|
||||||
|
[browser_UITour_detach_tab.js]
|
||||||
[browser_UITour_registerPageID.js]
|
[browser_UITour_registerPageID.js]
|
||||||
[browser_UITour_sync.js]
|
[browser_UITour_sync.js]
|
||||||
[browser_taskbar_preview.js]
|
[browser_taskbar_preview.js]
|
||||||
|
|
|
||||||
80
browser/modules/test/browser_UITour_detach_tab.js
Normal file
80
browser/modules/test/browser_UITour_detach_tab.js
Normal 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
Loading…
Reference in a new issue