Bug 595965 - App tabs bleed out of the group box r=ian+ehsan, a=blocking

This commit is contained in:
Mihai Sucan 2011-02-04 09:45:41 -08:00
Родитель 8c16a168bb
Коммит 6dd548e1af
7 изменённых файлов: 334 добавлений и 22 удалений

Просмотреть файл

@ -26,6 +26,7 @@
* Raymond Lee <raymond@appcoast.com>
* Tim Taubert <tim.taubert@gmx.de>
* Sean Dunn <seanedunn@yahoo.com>
* Mihai Sucan <mihai.sucan@gmail.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
@ -226,9 +227,12 @@ function GroupItem(listOfEls, options) {
.hide();
// ___ app tabs: create app tab tray and populate it
let appTabTrayContainer = iQ("<div/>")
.addClass("appTabTrayContainer")
.appendTo($container);
this.$appTabTray = iQ("<div/>")
.addClass("appTabTray")
.appendTo($container);
.appendTo(appTabTrayContainer);
AllTabs.tabs.forEach(function(xulTab) {
if (xulTab.pinned && xulTab.ownerDocument.defaultView == gWindow)
@ -375,6 +379,74 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.$titleShield.css(css);
},
// ----------
// Function: adjustAppTabTray
// Used to adjust the appTabTray size, to split the appTabIcons across
// multiple columns when needed - if the groupItem size is too small.
//
// Parameters:
// arrangeGroup - rearrange the groupItem if the number of appTab columns
// changes. If true, then this.arrange() is called, otherwise not.
adjustAppTabTray: function GroupItem_adjustAppTabTray(arrangeGroup) {
let icons = iQ(".appTabIcon", this.$appTabTray);
let container = iQ(this.$appTabTray[0].parentNode);
if (!icons.length) {
// There are no icons, so hide the appTabTray if needed.
if (parseInt(container.css("width")) != 0) {
this.$appTabTray.css("-moz-column-count", 0);
this.$appTabTray.css("height", 0);
container.css("width", 0);
container.css("height", 0);
if (container.hasClass("appTabTrayContainerTruncated"))
container.removeClass("appTabTrayContainerTruncated");
if (arrangeGroup)
this.arrange();
}
return;
}
let iconBounds = iQ(icons[0]).bounds();
let boxBounds = this.getBounds();
let contentHeight = boxBounds.height -
parseInt(container.css("top")) -
this.$resizer.height();
let rows = Math.floor(contentHeight / iconBounds.height);
let columns = Math.ceil(icons.length / rows);
let columnsGap = parseInt(this.$appTabTray.css("-moz-column-gap"));
let iconWidth = iconBounds.width + columnsGap;
let maxColumns = Math.floor((boxBounds.width * 0.20) / iconWidth);
if (columns > maxColumns)
container.addClass("appTabTrayContainerTruncated");
else if (container.hasClass("appTabTrayContainerTruncated"))
container.removeClass("appTabTrayContainerTruncated");
// Need to drop the -moz- prefix when Gecko makes it obsolete.
// See bug 629452.
if (parseInt(this.$appTabTray.css("-moz-column-count")) != columns)
this.$appTabTray.css("-moz-column-count", columns);
if (parseInt(this.$appTabTray.css("height")) != contentHeight) {
this.$appTabTray.css("height", contentHeight + "px");
container.css("height", contentHeight + "px");
}
let fullTrayWidth = iconWidth * columns - columnsGap;
if (parseInt(this.$appTabTray.css("width")) != fullTrayWidth)
this.$appTabTray.css("width", fullTrayWidth + "px");
let trayWidth = iconWidth * Math.min(columns, maxColumns) - columnsGap;
if (parseInt(container.css("width")) != trayWidth) {
container.css("width", trayWidth + "px");
// Rearrange the groupItem if the width changed.
if (arrangeGroup)
this.arrange();
}
},
// ----------
// Function: getContentBounds
// Returns a <Rect> for the groupItem's content area (which doesn't include the title, etc).
@ -384,7 +456,11 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
box.top += titleHeight;
box.height -= titleHeight;
var appTabTrayWidth = this.$appTabTray.width();
let appTabTrayContainer = iQ(this.$appTabTray[0].parentNode);
var appTabTrayWidth = appTabTrayContainer.width();
if (appTabTrayWidth)
appTabTrayWidth += parseInt(appTabTrayContainer.css(UI.rtl ? "left" : "right"));
box.width -= appTabTrayWidth;
if (UI.rtl) {
box.left += appTabTrayWidth;
@ -453,6 +529,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
var offset = new Point(rect.left - this.bounds.left, rect.top - this.bounds.top);
this.bounds = new Rect(rect);
// Make sure the AppTab icons fit the new groupItem size.
if (css.width || css.height)
this.adjustAppTabTray();
// ___ Deal with children
if (css.width || css.height) {
this.arrange({animate: !immediately}); //(immediately ? 'sometimes' : true)});
@ -1054,11 +1134,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
// adjust the tray
let columnWidth = $appTab.width();
if (parseInt(this.$appTabTray.css("width")) != columnWidth) {
this.$appTabTray.css({width: columnWidth});
this.arrange();
}
this.adjustAppTabTray(true);
},
// ----------
@ -1074,10 +1150,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
// adjust the tray
if (!iQ(".appTabIcon", this.$appTabTray).length) {
this.$appTabTray.css({width: 0});
this.arrange();
}
this.adjustAppTabTray(true);
xulTab.removeEventListener("error", this._onAppTabError, false);
},

Просмотреть файл

@ -101,7 +101,7 @@ body {
position: absolute;
}
.appTabTray {
.appTabTrayContainer {
position: absolute;
}

Просмотреть файл

@ -66,6 +66,7 @@ _BROWSER_FILES = \
browser_tabview_bug595804.js \
browser_tabview_bug595930.js \
browser_tabview_bug595943.js \
browser_tabview_bug595965.js \
browser_tabview_bug596781.js \
browser_tabview_bug597248.js \
browser_tabview_bug597360.js \

Просмотреть файл

@ -0,0 +1,138 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Mihai Sucan <mihai.sucan@gmail.com>
* Raymond Lee <raymond@appcoast.com>
* Ian Gilman <ian@iangilman.com>
*/
function test() {
waitForExplicitFinish();
newWindowWithTabView(onTabViewShown);
}
function onTabViewShown(win) {
let TabView = win.TabView;
let gBrowser = win.gBrowser;
let document = win.document;
ok(TabView.isVisible(), "Tab View is visible");
let contentWindow = document.getElementById("tab-view").contentWindow;
let iQ = contentWindow.iQ;
// establish initial state
is(contentWindow.GroupItems.groupItems.length, 1,
"we start with one group (the default)");
is(gBrowser.tabs.length, 1, "we start with one tab");
let originalTab = gBrowser.tabs[0];
// create a group
let box = new contentWindow.Rect(20, 20, 210, 200);
let groupItem = new contentWindow.GroupItem([],
{ bounds: box, title: "test1" });
is(contentWindow.GroupItems.groupItems.length, 2, "we now have two groups");
contentWindow.GroupItems.setActiveGroupItem(groupItem);
// create a tab
let xulTabs = [];
xulTabs.push(gBrowser.loadOneTab("about:blank"));
is(gBrowser.tabs.length, 2, "we now have two tabs");
is(groupItem._children.length, 1, "the new tab was added to the group");
// make sure the group has no app tabs
is(appTabCount(groupItem), 0, "there are no app tab icons");
let tray = groupItem.$appTabTray;
let trayContainer = iQ(tray[0].parentNode);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
// pin the tab, make sure the TabItem goes away and the icon comes on
gBrowser.pinTab(xulTabs[0]);
is(groupItem._children.length, 0,
"the app tab's TabItem was removed from the group");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
isnot(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is visible");
let iconHeight = iQ(iQ(".appTabIcon", tray)[0]).height();
let trayHeight = parseInt(trayContainer.css("height"));
let rows = Math.floor(trayHeight / iconHeight);
let icons = rows * 2;
// add enough tabs to have two columns
for (let i = 1; i < icons; i++) {
xulTabs.push(gBrowser.loadOneTab("about:blank"));
gBrowser.pinTab(xulTabs[i]);
}
is(appTabCount(groupItem), icons, "number of app tab icons is correct");
is(tray.css("-moz-column-count"), 2,
"$appTabTray column count is 2");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// add one more tab
xulTabs.push(gBrowser.loadOneTab("about:blank"));
gBrowser.pinTab(xulTabs[xulTabs.length-1]);
is(tray.css("-moz-column-count"), 3,
"$appTabTray column count is 3");
ok(trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container hasClass .appTabTrayContainerTruncated");
// remove all but one app tabs
for (let i = 1; i < xulTabs.length; i++)
gBrowser.removeTab(xulTabs[i]);
is(tray.css("-moz-column-count"), 1,
"$appTabTray column count is 1");
is(appTabCount(groupItem), 1, "there's now one app tab icon");
ok(!trayContainer.hasClass("appTabTrayContainerTruncated"),
"$appTabTray container does not have .appTabTrayContainerTruncated");
// unpin the last remaining tab
gBrowser.unpinTab(xulTabs[0]);
is(parseInt(trayContainer.css("width")), 0,
"$appTabTray container is not visible");
is(appTabCount(groupItem), 0, "there are no app tab icons");
is(groupItem._children.length, 1, "the normal tab shows in the group");
gBrowser.removeTab(xulTabs[0]);
// close the group
groupItem.close();
hideTabView(function() {
ok(!TabView.isVisible(), "Tab View is hidden");
is(contentWindow.GroupItems.groupItems.length, 1,
"we finish with one group");
is(gBrowser.tabs.length, 1, "we finish with one tab");
win.close();
executeSoon(finish);
}, win);
}
function appTabCount(groupItem) {
return groupItem.container.getElementsByClassName("appTabIcon").length;
}

Просмотреть файл

@ -100,7 +100,8 @@ html[dir=rtl] .close {
left: 6px;
}
.close:hover {
.close:hover,
.appTabIcon:hover {
opacity: 1.0;
}
@ -124,7 +125,8 @@ html[dir=rtl] .expander {
}
.close:hover,
.expander:hover {
.expander:hover,
.appTabIcon:hover {
-moz-transition-property: opacity;
-moz-transition-duration: 0.5s;
-moz-transition-timing-function: ease-out;
@ -245,20 +247,52 @@ html[dir=rtl] .overlay {
box-shadow: -3px 3px 5.5px rgba(0,0,0,.5);
}
.appTabTray {
.appTabTrayContainer {
top: 34px;
right: 1px;
-moz-border-start: 1px solid #E1E1E1;
padding: 0 5px;
overflow-x: hidden;
text-align: start;
line-height: 0;
}
html[dir=rtl] .appTabTray {
html[dir=rtl] .appTabTrayContainer {
right: auto;
left: 1px;
}
.appTabTray {
display: inline-block;
-moz-column-width: 16px;
-moz-column-count: 0;
-moz-column-gap: 5px;
}
.appTabTrayContainerTruncated {
padding-bottom: 7px;
}
.appTabTrayContainerTruncated:after {
content: "…";
position: absolute;
bottom: 2px;
left: 0;
display: block;
width: 100%;
height: 15px;
line-height: 15px;
text-align: center;
font-size: 15px;
}
.appTabIcon {
width: 16px;
height: 16px;
cursor: pointer;
opacity: 0.8;
padding-bottom: 3px;
display: block;
}
.undo {

Просмотреть файл

@ -115,7 +115,8 @@ html[dir=rtl] .expander {
}
.close:hover,
.expander:hover {
.expander:hover,
.appTabIcon:hover {
-moz-transition-property: opacity;
-moz-transition-duration: 0.5s;
-moz-transition-timing-function: ease-out;
@ -239,20 +240,52 @@ html[dir=rtl] .overlay {
box-shadow: -3px 3px 5.5px rgba(0,0,0,.5);
}
.appTabTray {
.appTabTrayContainer {
top: 34px;
right: 1px;
-moz-border-start: 1px solid #E1E1E1;
padding: 0 5px;
overflow-x: hidden;
text-align: start;
line-height: 0;
}
html[dir=rtl] .appTabTray {
html[dir=rtl] .appTabTrayContainer {
right: auto;
left: 1px;
}
.appTabTray {
display: inline-block;
-moz-column-width: 16px;
-moz-column-count: 0;
-moz-column-gap: 5px;
}
.appTabTrayContainerTruncated {
padding-bottom: 7px;
}
.appTabTrayContainerTruncated:after {
content: "…";
position: absolute;
bottom: 2px;
left: 0;
display: block;
width: 100%;
height: 15px;
line-height: 15px;
text-align: center;
font-size: 15px;
}
.appTabIcon {
width: 16px;
height: 16px;
cursor: pointer;
opacity: 0.8;
padding-bottom: 3px;
display: block;
}
.undo {

Просмотреть файл

@ -118,7 +118,8 @@ html[dir=rtl] .expander {
}
.close:hover,
.expander:hover {
.expander:hover,
.appTabIcon:hover {
-moz-transition-property: opacity;
-moz-transition-duration: 0.5s;
-moz-transition-timing-function: ease-out;
@ -262,20 +263,52 @@ html[dir=rtl] .overlay {
box-shadow: -3px 3px 5.5px rgba(0,0,0,.5);
}
.appTabTray {
.appTabTrayContainer {
top: 34px;
right: 1px;
-moz-border-start: 1px solid #E1E1E1;
padding: 0 5px;
overflow-x: hidden;
text-align: start;
line-height: 0;
}
html[dir=rtl] .appTabTray {
html[dir=rtl] .appTabTrayContainer {
right: auto;
left: 1px;
}
.appTabTray {
display: inline-block;
-moz-column-width: 16px;
-moz-column-count: 0;
-moz-column-gap: 5px;
}
.appTabTrayContainerTruncated {
padding-bottom: 7px;
}
.appTabTrayContainerTruncated:after {
content: "…";
position: absolute;
bottom: 2px;
left: 0;
display: block;
width: 100%;
height: 15px;
line-height: 15px;
text-align: center;
font-size: 15px;
}
.appTabIcon {
width: 16px;
height: 16px;
cursor: pointer;
opacity: 0.8;
padding-bottom: 3px;
display: block;
}
.undo {