Bug 582116 - Provide a way to show certain tabs and get visible tabs

Add showOnlyTheseTabs and visibleTabs to tabbrowser and update various uses such as tab selection. Test that tabs get hidden/shown when using this API and tab selection only deal with visible tabs while making sure there's always a visible tab.
This commit is contained in:
Edward Lee 2010-07-29 16:39:57 -07:00
parent 8cab72cdf4
commit bf6bb3f5ee
6 changed files with 189 additions and 38 deletions

View File

@ -480,9 +480,9 @@ var PlacesCommandHook = {
var tabList = [];
var seenURIs = {};
var browsers = gBrowser.browsers;
for (var i = 0; i < browsers.length; ++i) {
let uri = browsers[i].currentURI;
let tabs = gBrowser.visibleTabs;
for (let i = 0; i < tabs.length; ++i) {
let uri = tabs[i].linkedBrowser.currentURI;
// skip redundant entries
if (uri.spec in seenURIs)

View File

@ -215,12 +215,13 @@ var ctrlTab = {
if (this._tabList)
return this._tabList;
var list = Array.slice(gBrowser.tabs);
let list = gBrowser.visibleTabs;
if (this._closing)
this.detachTab(this._closing, list);
for (let i = 0; i < gBrowser.tabContainer.selectedIndex; i++)
// Rotate the list until the selected tab is first
while (!list[0].selected)
list.push(list.shift());
if (this.recentlyUsedLimit != 0) {
@ -462,11 +463,12 @@ var ctrlTab = {
} else if (!event.shiftKey) {
event.preventDefault();
event.stopPropagation();
if (gBrowser.tabs.length > 2) {
let tabs = gBrowser.visibleTabs;
if (tabs.length > 2) {
this.open();
} else if (gBrowser.tabs.length == 2) {
gBrowser.selectedTab = gBrowser.selectedTab.nextSibling ||
gBrowser.selectedTab.previousSibling;
} else if (tabs.length == 2) {
let index = gBrowser.selectedTab == tabs[0] ? 1 : 0;
gBrowser.selectedTab = tabs[index];
}
}
}
@ -664,7 +666,7 @@ var allTabs = {
Array.forEach(this.previews, function (preview) {
var tab = preview._tab;
var matches = 0;
if (filter.length) {
if (filter.length && !tab.hidden) {
let tabstring = tab.linkedBrowser.currentURI.spec;
try {
tabstring = decodeURI(tabstring);
@ -673,7 +675,7 @@ var allTabs = {
for (let i = 0; i < filter.length; i++)
matches += tabstring.indexOf(filter[i]) > -1;
}
if (matches < filter.length) {
if (matches < filter.length || tab.hidden) {
preview.hidden = true;
}
else {

View File

@ -6741,7 +6741,7 @@ var gBookmarkAllTabsHandler = {
},
_updateCommandState: function BATH__updateCommandState(aTabClose) {
var numTabs = gBrowser.tabs.length;
let numTabs = gBrowser.visibleTabs.length;
// The TabClose event is fired before the tab is removed from the DOM
if (aTabClose)
@ -7764,7 +7764,7 @@ var TabContextMenu = {
updateContextMenu: function updateContextMenu(aPopupMenu) {
this.contextTab = document.popupNode.localName == "tab" ?
document.popupNode : gBrowser.selectedTab;
var disabled = gBrowser.tabs.length == 1;
let disabled = gBrowser.visibleTabs.length == 1;
// Enable the "Close Tab" menuitem when the window doesn't close with the last tab.
document.getElementById("context_closeTab").disabled =
@ -7786,7 +7786,7 @@ var TabContextMenu = {
// Disable "Close other Tabs" if there is only one unpinned tab and
// hide it when the user rightclicked on a pinned tab.
var unpinnedTabs = gBrowser.tabs.length - gBrowser._numPinnedTabs;
let unpinnedTabs = gBrowser.visibleTabs.length - gBrowser._numPinnedTabs;
document.getElementById("context_closeOtherTabs").disabled = unpinnedTabs <= 1;
document.getElementById("context_closeOtherTabs").hidden = this.contextTab.pinned;
}

View File

@ -88,6 +88,8 @@
<field name="tabs" readonly="true">
this.tabContainer.childNodes;
</field>
<property name="visibleTabs" readonly="true"
onget="return Array.filter(this.tabs, function(tab) !tab.hidden);"/>
<field name="mURIFixup" readonly="true">
Components.classes["@mozilla.org/docshell/urifixup;1"]
.getService(Components.interfaces.nsIURIFixup);
@ -749,6 +751,7 @@
newBrowser.setAttribute("type", "content-primary");
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
this.mCurrentTab.hidden = false;
if (updatePageReport)
this.mCurrentBrowser.updatePageReport();
@ -1218,7 +1221,7 @@
var tabsToClose = this.tabs.length;
if (!aAll)
tabsToClose -= 1 + gBrowser._numPinnedTabs;
tabsToClose = this.visibleTabs.length - (1 + this._numPinnedTabs);
if (tabsToClose <= 1)
return true;
@ -1269,11 +1272,12 @@
return;
if (this.warnAboutClosingTabs(false)) {
let tabs = this.visibleTabs;
this.selectedTab = aTab;
for (let i = this.tabs.length - 1; i >= 0; --i) {
if (this.tabs[i] != aTab && !this.tabs[i].pinned)
this.removeTab(this.tabs[i]);
for (let i = tabs.length - 1; i >= 0; --i) {
if (tabs[i] != aTab && !tabs[i].pinned)
this.removeTab(tabs[i]);
}
}
]]>
@ -1505,21 +1509,22 @@
return;
}
var tab = aTab;
let removing = this._removingTabs;
let ignoreRemoving = function(tab) removing.indexOf(tab) == -1;
// Switch to a visible tab unless there aren't any remaining
let remainingTabs = this.visibleTabs.filter(ignoreRemoving);
if (remainingTabs.length == 0)
remainingTabs = Array.filter(this.tabs, ignoreRemoving);
// Try to find a remaining tab that comes after the given tab
var tab = aTab;
do {
tab = tab.nextSibling;
} while (tab && this._removingTabs.indexOf(tab) != -1);
} while (tab && remainingTabs.indexOf(tab) == -1);
if (!tab) {
tab = aTab;
do {
tab = tab.previousSibling;
} while (tab && this._removingTabs.indexOf(tab) != -1);
}
this.selectedTab = tab;
// If no tab was found, give the end of the remaining tabs
this.selectedTab = tab ? tab : remainingTabs.pop();
]]>
</body>
</method>
@ -1592,10 +1597,11 @@
<method name="reloadAllTabs">
<body>
<![CDATA[
var l = this.mPanelContainer.childNodes.length;
let tabs = this.visibleTabs;
let l = tabs.length;
for (var i = 0; i < l; i++) {
try {
this.getBrowserAtIndex(i).reload();
this.getBrowserForTab(tabs[i]).reload();
} catch (e) {
// ignore failure to reload so others will be reloaded
}
@ -1692,19 +1698,33 @@
</body>
</method>
<method name="showOnlyTheseTabs">
<parameter name="aTabs"/>
<body>
<![CDATA[
Array.forEach(this.tabs, function(tab) {
tab.hidden = aTabs.indexOf(tab) == -1 && !tab.pinned && !tab.selected;
});
]]>
</body>
</method>
<method name="selectTabAtIndex">
<parameter name="aIndex"/>
<parameter name="aEvent"/>
<body>
<![CDATA[
let tabs = this.visibleTabs;
// count backwards for aIndex < 0
if (aIndex < 0)
aIndex += this.tabs.length;
aIndex += tabs.length;
if (aIndex >= 0 &&
aIndex < this.tabs.length &&
aIndex != this.tabContainer.selectedIndex)
this.selectedTab = this.tabs[aIndex];
if (aIndex >= 0 && aIndex < tabs.length) {
let nextTab = tabs[aIndex];
if (nextTab != this.selectedTab)
this.selectedTab = nextTab;
}
if (aEvent) {
aEvent.preventDefault();
@ -1746,7 +1766,7 @@
<parameter name="aTab"/>
<body>
<![CDATA[
if (this.tabs.length == 1)
if (this.visibleTabs.length == 1)
return null;
// tell a new window to take the "dropped" tab
@ -2508,6 +2528,8 @@
this.setAttribute("closebuttons", "noclose");
else {
let tab = this.childNodes.item(this.tabbrowser._numPinnedTabs);
if (tab && tab.hidden)
tab = this.tabbrowser.visibleTabs[0];
if (tab && tab.getBoundingClientRect().width > this.mTabClipWidth)
this.setAttribute("closebuttons", "alltabs");
else
@ -3288,7 +3310,7 @@
<![CDATA[
// set up the menu popup
var tabcontainer = gBrowser.tabContainer;
var tabs = tabcontainer.childNodes;
let tabs = gBrowser.visibleTabs;
// Listen for changes in the tab bar.
tabcontainer.addEventListener("TabOpen", this, false);

View File

@ -164,6 +164,7 @@ _BROWSER_FILES = \
browser_selectTabAtIndex.js \
browser_tabfocus.js \
browser_tabs_owner.js \
browser_visibleTabs.js \
discovery.html \
moz.png \
test_bug435035.html \

View File

@ -0,0 +1,126 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is tabbrowser visibleTabs test.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Edward Lee <edilee@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
function test() {
// There should be one tab when we start the test
let [origTab] = gBrowser.visibleTabs;
// Add a tab that will get pinned
let pinned = gBrowser.addTab();
gBrowser.pinTab(pinned);
let testTab = gBrowser.addTab();
let visible = gBrowser.visibleTabs;
is(visible.length, 3, "3 tabs should be open");
is(visible[0], pinned, "the pinned tab is first");
is(visible[1], origTab, "original tab is next");
is(visible[2], testTab, "last created tab is last");
// Only show the test tab (but also get pinned and selected)
is(gBrowser.selectedTab, origTab, "sanity check that we're on the original tab");
gBrowser.showOnlyTheseTabs([testTab]);
is(gBrowser.visibleTabs.length, 3, "all 3 tabs are still visible");
// Select the test tab and only show that (and pinned)
gBrowser.selectedTab = testTab;
gBrowser.showOnlyTheseTabs([testTab]);
visible = gBrowser.visibleTabs;
is(visible.length, 2, "2 tabs should be visible including the pinned");
is(visible[0], pinned, "first is pinned");
is(visible[1], testTab, "next is the test tab");
is(gBrowser.tabs.length, 3, "3 tabs should still be open");
gBrowser.selectTabAtIndex(0);
is(gBrowser.selectedTab, pinned, "first tab is pinned");
gBrowser.selectTabAtIndex(1);
is(gBrowser.selectedTab, testTab, "second tab is the test tab");
gBrowser.selectTabAtIndex(2);
is(gBrowser.selectedTab, testTab, "no third tab, so no change");
gBrowser.selectTabAtIndex(0);
is(gBrowser.selectedTab, pinned, "switch back to the pinned");
gBrowser.selectTabAtIndex(2);
is(gBrowser.selectedTab, pinned, "no third tab, so no change");
gBrowser.selectTabAtIndex(-1);
is(gBrowser.selectedTab, testTab, "last tab is the test tab");
gBrowser.tabContainer.advanceSelectedTab(1, true);
is(gBrowser.selectedTab, pinned, "wrapped around the end to pinned");
gBrowser.tabContainer.advanceSelectedTab(1, true);
is(gBrowser.selectedTab, testTab, "next to test tab");
gBrowser.tabContainer.advanceSelectedTab(1, true);
is(gBrowser.selectedTab, pinned, "next to pinned again");
gBrowser.tabContainer.advanceSelectedTab(-1, true);
is(gBrowser.selectedTab, testTab, "going backwards to last tab");
gBrowser.tabContainer.advanceSelectedTab(-1, true);
is(gBrowser.selectedTab, pinned, "next to pinned");
gBrowser.tabContainer.advanceSelectedTab(-1, true);
is(gBrowser.selectedTab, testTab, "next to test tab again");
// Try showing all tabs
gBrowser.showOnlyTheseTabs(Array.slice(gBrowser.tabs));
is(gBrowser.visibleTabs.length, 3, "all 3 tabs are visible again");
// Select the pinned tab and show the testTab to make sure selection updates
gBrowser.selectedTab = pinned;
gBrowser.showOnlyTheseTabs([testTab]);
is(gBrowser.tabs[1], origTab, "make sure origTab is in the middle");
is(origTab.hidden, true, "make sure it's hidden");
gBrowser.removeTab(pinned);
is(gBrowser.selectedTab, testTab, "making sure origTab was skipped");
is(gBrowser.visibleTabs.length, 1, "only testTab is there");
// Only show one of the non-pinned tabs (but testTab is selected)
gBrowser.showOnlyTheseTabs([origTab]);
is(gBrowser.visibleTabs.length, 2, "got 2 tabs");
// Now really only show one of the tabs
gBrowser.showOnlyTheseTabs([testTab]);
visible = gBrowser.visibleTabs;
is(visible.length, 1, "only the original tab is visible");
is(visible[0], testTab, "it's the original tab");
is(gBrowser.tabs.length, 2, "still have 2 open tabs");
// Close the last visible tab and make sure we still get a visible tab
gBrowser.removeTab(testTab);
is(gBrowser.visibleTabs.length, 1, "only orig is left and visible");
is(gBrowser.tabs.length, 1, "sanity check that it matches");
is(gBrowser.selectedTab, origTab, "got the orig tab");
is(origTab.hidden, false, "and it's not hidden -- visible!");
}