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
	
	 Gijs Kruitbosch
						Gijs Kruitbosch