diff --git a/browser/base/content/tabview/groupitems.js b/browser/base/content/tabview/groupitems.js index 6ba8dbe01bb..664d48eb445 100644 --- a/browser/base/content/tabview/groupitems.js +++ b/browser/base/content/tabview/groupitems.js @@ -767,7 +767,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), { return (groupItem != self && !groupItem.getChildren().length); }); let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup()); - group.newTab(); + group.newTab(null, { closedLastTab: true }); } this.destroy(); @@ -1739,14 +1739,16 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), { // ---------- // Function: newTab // Creates a new tab within this groupItem. - newTab: function GroupItem_newTab(url) { - UI.setActive(this, { dontSetActiveTabInGroup: true }); - let newTab = gBrowser.loadOneTab(url || "about:blank", {inBackground: true}); + // Parameters: + // url - the new tab should open this url as well + // options - the options object + // closedLastTab - boolean indicates the last tab has just been closed + newTab: function GroupItem_newTab(url, options) { + if (options && options.closedLastTab) + UI.closedLastTabInTabView = true; - // TabItems will have handled the new tab and added the tabItem property. - // We don't have to check if it's an app tab (and therefore wouldn't have a - // TabItem), since we've just created it. - newTab._tabViewTabItem.zoomIn(!url); + UI.setActive(this, { dontSetActiveTabInGroup: true }); + gBrowser.loadOneTab(url || "about:blank", { inBackground: false }); }, // ---------- diff --git a/browser/base/content/tabview/tabitems.js b/browser/base/content/tabview/tabitems.js index f6e387147af..7e91a1b01e8 100644 --- a/browser/base/content/tabview/tabitems.js +++ b/browser/base/content/tabview/tabitems.js @@ -380,7 +380,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { } } else { // create tab by double click is handled in UI_init(). - if (!TabItems.creatingNewOrphanTab) + if (!UI.creatingNewOrphanTab) GroupItems.newTab(self, {immediately: true}); } @@ -564,7 +564,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { }); group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup()); } - group.newTab(); + group.newTab(null, { closedLastTab: true }); } // when "TabClose" event is fired, the browser tab is about to close and our // item "close" is fired before the browser tab actually get closed. @@ -666,6 +666,8 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { } if (self.parent && self.parent.expanded) self.parent.collapse(); + + self._sendToSubscribers("zoomedIn"); } let animateZoom = gPrefBranch.getBoolPref("animate_zoom"); @@ -804,7 +806,6 @@ let TabItems = { _lastUpdateTime: Date.now(), _eventListeners: [], _pauseUpdateForTest: false, - creatingNewOrphanTab: false, tempCanvas: null, _reconnectingPaused: false, tabItemPadding: {}, diff --git a/browser/base/content/tabview/ui.js b/browser/base/content/tabview/ui.js index 9dacb71cda9..ff9c4642109 100644 --- a/browser/base/content/tabview/ui.js +++ b/browser/base/content/tabview/ui.js @@ -139,6 +139,14 @@ let UI = { // Used to prevent keypress being handled after quitting search mode. ignoreKeypressForSearch: false, + // Variable: creatingNewOrphanTab + // Used to keep track of whether we are creating a new oprhan tab or not. + creatingNewOrphanTab: false, + + // Variable: _lastOpenedTab + // Used to keep track of the last opened tab. + _lastOpenedTab: null, + // ---------- // Function: toString // Prints [UI] for debug use @@ -196,20 +204,21 @@ let UI = { (self._lastClickPositions.y - self.DBLCLICK_OFFSET) <= e.clientY && (self._lastClickPositions.y + self.DBLCLICK_OFFSET) >= e.clientY) { self.setActive(null); - TabItems.creatingNewOrphanTab = true; - - let newTab = - gBrowser.loadOneTab("about:blank", { inBackground: true }); + self.creatingNewOrphanTab = true; let box = new Rect(e.clientX - Math.floor(TabItems.tabWidth/2), e.clientY - Math.floor(TabItems.tabHeight/2), TabItems.tabWidth, TabItems.tabHeight); + let newTab = + gBrowser.loadOneTab("about:blank", { inBackground: false }); + newTab._tabViewTabItem.setBounds(box, true); newTab._tabViewTabItem.pushAway(true); self.setActive(newTab._tabViewTabItem); - TabItems.creatingNewOrphanTab = false; + self.creatingNewOrphanTab = false; + // the bounds of tab item is set and we can zoom in now. newTab._tabViewTabItem.zoomIn(true); self._lastClick = 0; @@ -717,6 +726,8 @@ let UI = { // if it's an app tab, add it to all the group items if (tab.pinned) GroupItems.addAppTab(tab); + else if (self.isTabViewVisible()) + self._lastOpenedTab = tab; }; // TabClose @@ -852,30 +863,40 @@ let UI = { // Function: onTabSelect // Called when the user switches from one tab to another outside of the TabView UI. onTabSelect: function UI_onTabSelect(tab) { - let currentTab = this._currentTab; this._currentTab = tab; - // if the last visible tab has just been closed, don't show the chrome UI. - if (this.isTabViewVisible() && - (this._closedLastVisibleTab || this._closedSelectedTabInTabView || - this.restoredClosedTab)) { - if (this.restoredClosedTab) { - // when the tab view UI is being displayed, update the thumb for the - // restored closed tab after the page load - tab.linkedBrowser.addEventListener("load", function (event) { - tab.linkedBrowser.removeEventListener("load", arguments.callee, true); - TabItems._update(tab); - }, true); + if (this.isTabViewVisible()) { + if (!this.restoredClosedTab && this._lastOpenedTab == tab && + tab._tabViewTabItem) { + if (!this.creatingNewOrphanTab) + tab._tabViewTabItem.zoomIn(true); + this._lastOpenedTab = null; + return; + } + if (this._closedLastVisibleTab || + (this._closedSelectedTabInTabView && !this.closedLastTabInTabView) || + this.restoredClosedTab) { + if (this.restoredClosedTab) { + // when the tab view UI is being displayed, update the thumb for the + // restored closed tab after the page load + tab.linkedBrowser.addEventListener("load", function (event) { + tab.linkedBrowser.removeEventListener("load", arguments.callee, true); + TabItems._update(tab); + }, true); + } + this._closedLastVisibleTab = false; + this._closedSelectedTabInTabView = false; + this.closedLastTabInTabView = false; + this.restoredClosedTab = false; + return; } - this._closedLastVisibleTab = false; - this._closedSelectedTabInTabView = false; - this.restoredClosedTab = false; - return; } // reset these vars, just in case. this._closedLastVisibleTab = false; this._closedSelectedTabInTabView = false; + this.closedLastTabInTabView = false; this.restoredClosedTab = false; + this._lastOpenedTab = null; // if TabView is visible but we didn't just close the last tab or // selected tab, show chrome. @@ -887,12 +908,7 @@ let UI = { if (this._currentTab != tab) return; - let oldItem = null; let newItem = null; - - if (currentTab && currentTab._tabViewTabItem) - oldItem = currentTab._tabViewTabItem; - // update the tab bar for the new tab's group if (tab && tab._tabViewTabItem) { if (!TabItems.reconnectingPaused()) { @@ -1490,14 +1506,14 @@ let UI = { return (!groupItem.hidden && groupItem.getChildren().length > 0); }); // no pinned tabs, no visible groups and no orphaned tabs: open a new - // group. open a blank tab and return + // group, a blank tab and return if (!unhiddenGroups.length && !GroupItems.getOrphanedTabs().length) { let emptyGroups = GroupItems.groupItems.filter(function (groupItem) { return (!groupItem.hidden && !groupItem.getChildren().length); }); let group = (emptyGroups.length ? emptyGroups[0] : GroupItems.newGroup()); if (!gBrowser._numPinnedTabs) { - group.newTab(); + group.newTab(null, { closedLastTab: true }); return; } } diff --git a/browser/base/content/test/tabview/browser_tabview_bug587276.js b/browser/base/content/test/tabview/browser_tabview_bug587276.js index 9c6e2866c06..defed5a2e39 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug587276.js +++ b/browser/base/content/test/tabview/browser_tabview_bug587276.js @@ -36,20 +36,23 @@ function test3() { ok(!contentWindow.isSearchEnabled(), "The search is disabled") is(gBrowser.tabs.length, 1, "There is one tab before cmd/ctrl + t is pressed"); - EventUtils.synthesizeKey("t", { accelKey: true }, contentWindow); - is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + t is pressed"); - gBrowser.tabs[0].linkedBrowser.loadURI("about:robots"); - gBrowser.tabs[1].linkedBrowser.loadURI("http://example.com/"); + whenTabViewIsHidden(function() { + is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + t is pressed"); - afterAllTabsLoaded(function () { - showTabView(test4); + gBrowser.tabs[0].linkedBrowser.loadURI("about:robots"); + gBrowser.tabs[1].linkedBrowser.loadURI("http://example.com/"); + + afterAllTabsLoaded(function () { + showTabView(test4); + }); }); + EventUtils.synthesizeKey("t", { accelKey: true }, contentWindow); } function test4() { is(gBrowser.tabs.length, 2, "There are two tabs"); - + let onTabClose = function() { gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, true); executeSoon(function() { @@ -59,7 +62,7 @@ function test4() { is(gBrowser.tabs.length, 2, "There are two tabs after restoring one"); gBrowser.tabs[0].linkedBrowser.loadURI("about:blank"); - gBrowser.removeTab(gBrowser.tabs[1]); + gBrowser.selectedTab = gBrowser.tabs[0]; test8(); }); }; @@ -69,14 +72,14 @@ function test4() { // below key combination shouldn't trigger actions in tabview UI function test8() { - let newTab = gBrowser.loadOneTab("about:blank", { inBackground: true }); + showTabView(function() { + is(gBrowser.tabs.length, 2, "There are two tabs before cmd/ctrl + w is pressed"); + EventUtils.synthesizeKey("w", { accelKey: true }, contentWindow); + is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + w is pressed"); - is(gBrowser.tabs.length, 2, "There are two tabs before cmd/ctrl + w is pressed"); - EventUtils.synthesizeKey("w", { accelKey: true }, contentWindow); - is(gBrowser.tabs.length, 2, "There are two tabs after cmd/ctrl + w is pressed"); - - gBrowser.removeTab(newTab); - test9(); + gBrowser.removeTab(gBrowser.tabs[1]); + test9(); + }); } function test9() { diff --git a/browser/base/content/test/tabview/browser_tabview_bug598600.js b/browser/base/content/test/tabview/browser_tabview_bug598600.js index 32c8a0094cd..2d6a70a0ecb 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug598600.js +++ b/browser/base/content/test/tabview/browser_tabview_bug598600.js @@ -69,6 +69,6 @@ function test() { finish(); } newWin.addEventListener("tabviewshown", onTabViewShow, false); - newWin.TabView.toggle(); + waitForFocus(function() { newWin.TabView.toggle(); }); }, false); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug622872.js b/browser/base/content/test/tabview/browser_tabview_bug622872.js index f10c5cb6957..094dc7e4cd7 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug622872.js +++ b/browser/base/content/test/tabview/browser_tabview_bug622872.js @@ -64,11 +64,8 @@ function part1(win) { ok(!contentWindow.UI.getActiveOrphanTab(), "There is no active orphan tab."); ok(win.TabView.isVisible(), "Tab View is visible."); - - win.gBrowser.tabContainer.addEventListener("TabSelect", function() { - win.gBrowser.tabContainer.removeEventListener("TabSelect", arguments.callee, false); - executeSoon(part4); - }, false); + + whenTabViewIsHidden(part4, win); win.document.getElementById("cmd_newNavigatorTab").doCommand(); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug633190.js b/browser/base/content/test/tabview/browser_tabview_bug633190.js new file mode 100644 index 00000000000..f7b9c0fdd1d --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug633190.js @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +let origTab = gBrowser.visibleTabs[0]; +let contentWindow; + +function test() { + waitForExplicitFinish(); + + test1(); +} + +// Open a new tab when the active tab item belongs to a group item. +function test1() { + registerCleanupFunction(function () TabView.hide()); + + showTabView(function() { + ok(origTab._tabViewTabItem.parent, "The original tab belongs to a group"); + + contentWindow = TabView.getContentWindow(); + contentWindow.UI.setActive(origTab._tabViewTabItem); + + testCreateTabAndThen(test2); + }); +} + +// Open a new tab when the active tab item is nothing. +function test2() { + showTabView(function() { + contentWindow.UI.setActive(null, { onlyRemoveActiveTab: true }); + + testCreateTabAndThen(test3); + }); +} + +// Open a new tab when the active tab item is an orphan tab. +function test3() { + showTabView(function() { + let groupItem = origTab._tabViewTabItem.parent; + let tabItems = groupItem.getChildren(); + is(tabItems.length, 3, "There are 3 tab items in the group"); + + let lastTabItem = tabItems[tabItems.length - 1]; + groupItem.remove(lastTabItem); + + let orphanedTabs = contentWindow.GroupItems.getOrphanedTabs(); + is(orphanedTabs.length, 1, "There should be 1 orphan tab"); + is(orphanedTabs[0], lastTabItem, "The tab item is the same as the orphan tab"); + + contentWindow.UI.setActive(lastTabItem); + + testCreateTabAndThen(function() { + hideTabView(finish); + }); + }); +} + +function testCreateTabAndThen(callback) { + ok(TabView.isVisible(), "Tab View is visible"); + + // detect tab open and zoomed in event. + let onTabOpen = function(event) { + gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, false); + + // ensure that the default tabview listener is called before so the + // tab._tabViewTabItem exists + executeSoon(function() { + let tab = event.target; + tabItem = tab._tabViewTabItem; + ok(tabItem, "Tab item is available after tab open"); + + registerCleanupFunction(function () gBrowser.removeTab(tab)) + + tabItem.addSubscriber(tabItem, "zoomedIn", function() { + tabItem.removeSubscriber(tabItem, "zoomedIn"); + + is(gBrowser.selectedTab, tab, + "The selected tab is the same as the newly opened tab"); + executeSoon(callback); + }); + }); + } + gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, false); + // use the menu item (the same as pressing cmd/ctrl + t) + document.getElementById("menu_newNavigatorTab").doCommand(); +} diff --git a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js b/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js index 43b76ea2973..a6f6ae27861 100644 --- a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js +++ b/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js @@ -22,61 +22,68 @@ function onTabViewLoadedAndShown() { ok(TabView.isVisible(), "Tab View is visible"); // Establish initial state - contentWindow = document.getElementById("tab-view").contentWindow; + contentWindow = document.getElementById("tab-view").contentWindow; verifyCleanState("start"); - + // register a clean up for private browsing just in case registerCleanupFunction(function() { pb.privateBrowsingEnabled = false; }); - + // create a group let box = new contentWindow.Rect(20, 20, 180, 180); let groupItem = new contentWindow.GroupItem([], {bounds: box, title: "test1"}); - let id = groupItem.id; + let id = groupItem.id; is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups"); registerCleanupFunction(function() { contentWindow.GroupItems.groupItem(id).close(); }); - + // make it the active group so new tabs will be added to it contentWindow.UI.setActive(groupItem); - + // collect the group titles let count = contentWindow.GroupItems.groupItems.length; for (let a = 0; a < count; a++) { let gi = contentWindow.GroupItems.groupItems[a]; groupTitles[a] = gi.getTitle(); } - + // Create a second tab - gBrowser.addTab("about:robots"); + gBrowser.loadOneTab("about:robots", { inBackground: false }); is(gBrowser.tabs.length, 2, "we now have 2 tabs"); registerCleanupFunction(function() { gBrowser.removeTab(gBrowser.tabs[1]); }); afterAllTabsLoaded(function() { - // Get normal tab urls - for (let a = 0; a < gBrowser.tabs.length; a++) - normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec); + showTabView(function() { + // Get normal tab urls + for (let a = 0; a < gBrowser.tabs.length; a++) + normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec); - // verify that we're all set up for our test - verifyNormal(); + // verify that we're all set up for our test + verifyNormal(); - // go into private browsing and make sure Tab View becomes hidden - togglePBAndThen(function() { - ok(!TabView.isVisible(), "Tab View is no longer visible"); - verifyPB(); - - // exit private browsing and make sure Tab View is shown again + // go into private browsing and make sure Tab View becomes hidden togglePBAndThen(function() { - ok(TabView.isVisible(), "Tab View is visible again"); - verifyNormal(); + whenTabViewIsHidden(function() { + ok(!TabView.isVisible(), "Tab View is no longer visible"); - hideTabView(onTabViewHidden); + verifyPB(); + + // exit private browsing and make sure Tab View is shown again + togglePBAndThen(function() { + whenTabViewIsShown(function() { + ok(TabView.isVisible(), "Tab View is visible again"); + verifyNormal(); + + hideTabView(onTabViewHidden); + }); + }); + }); }); - }); + }); }); }