fix for bug #318168, tab browsing improvements such as:

1)  when we have "too many" tabs in a window, allow the user to scroll through
the tabs.

2)  add events for when adding and removing tabs

initial patch by mconnor.  final patch r=mconnor
This commit is contained in:
sspitzer%mozilla.org 2006-06-26 22:35:08 +00:00
parent 38987b729d
commit 1b096a746f
9 changed files with 391 additions and 83 deletions

View File

@ -166,6 +166,8 @@ pref("browser.tabs.maxOpenBeforeWarn", 15);
// 0 = append, 1 = replace
pref("browser.tabs.loadGroup", 1);
pref("toolkit.scrollbox.scrollIncrement", 20);
// lets new tab/window load something different than first window
// -1 - use navigator startup preference
// 0 - loads blank page

View File

@ -1,5 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE bindings [
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<bindings id="arrowscrollboxBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
@ -13,7 +18,7 @@
<binding id="scrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
<content>
<xul:box class="box-inherit scrollbox-innerbox" xbl:inherits="orient,align,pack,dir">
<xul:box class="box-inherit scrollbox-innerbox" xbl:inherits="orient,align,pack,dir" flex="1">
<children/>
</xul:box>
</content>
@ -21,25 +26,97 @@
<binding id="arrowscrollbox" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
<content>
<xul:autorepeatbutton class="autorepeatbutton-up" collapsed="true"
oncommand="this.parentNode.scrollByIndex(-1); event.stopPropagation();"/>
<xul:autorepeatbutton class="autorepeatbutton-up" collapsed="true" xbl:inherits="orient,clicktoscroll"
onclick="handleOnClick(event, -1);"
oncommand="handleOnCommand(event, -1);"/>
<xul:scrollbox xbl:inherits="orient,align,pack,dir" flex="1">
<children/>
</xul:scrollbox>
<xul:autorepeatbutton class="autorepeatbutton-down" collapsed="true"
oncommand="this.parentNode.scrollByIndex(1); event.stopPropagation();"/>
<xul:autorepeatbutton class="autorepeatbutton-down" collapsed="true" xbl:inherits="orient,clicktoscroll"
onclick="handleOnClick(event, 1);"
oncommand="handleOnCommand(event, 1);"/>
</content>
<implementation>
<field name="_scrollIncrement">0</field>
<property name="scrollIncrement" readonly="true">
<getter><![CDATA[
if (!this._scrollIncrement) {
var pb2 =
Components.classes['@mozilla.org/preferences-service;1'].
getService(Components.interfaces.nsIPrefBranch2);
try {
this._scrollIncrement = pb2.getIntPref("toolkit.scrollbox.scrollIncrement");
}
catch (ex) {
this._scrollIncrement = 20;
}
}
return this._scrollIncrement;
]]></getter>
</property>
<field name="_scrollBoxObject">null</field>
<property name="scrollBoxObject" readonly="true">
<getter><![CDATA[
if (!this._scrollBoxObject) {
var kids = document.getAnonymousNodes(this);
this._scrollBoxObject = kids[1].boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject);
}
return this._scrollBoxObject;
]]></getter>
</property>
<method name="ensureElementIsVisible">
<parameter name="aElement"/>
<body><![CDATA[
this.scrollBoxObject.ensureElementIsVisible(aElement);
]]></body>
</method>
<method name="handleOnCommand">
<parameter name="aEvent"/>
<parameter name="aMultiple"/>
<body><![CDATA[
// don't scroll on mouseover if clicktoscroll="true"
if (this.getAttribute("clicktoscroll") != "true") {
var px = this.scrollIncrement * aMultiple;
this.scrollByPixels(px);
aEvent.stopPropagation();
}
]]></body>
</method>
<method name="handleOnClick">
<parameter name="aEvent"/>
<parameter name="aMultiple"/>
<body><![CDATA[
// only scroll by index on click if clicktoscroll="true"
if (this.getAttribute("clicktoscroll") == "true") {
this.scrollByIndex(aMultiple);
aEvent.stopPropagation();
}
]]></body>
</method>
<method name="scrollByIndex">
<parameter name="lines"/>
<body><![CDATA[
if (!("mScrollBoxObject" in this)) {
var kids = document.getAnonymousNodes(this);
this.mScrollBoxObject = kids[1].boxObject.QueryInterface(Components.interfaces.nsIScrollBoxObject);
}
this.scrollBoxObject.scrollByIndex(lines);
]]></body>
</method>
this.mScrollBoxObject.scrollByIndex(lines);
<method name="scrollByPixels">
<parameter name="px"/>
<body><![CDATA[
if (this.getAttribute("orient") == "horizontal") {
// if not ltr, we want to scroll the other direction
var actualPx = window.getComputedStyle(this.parentNode, "")
.direction == "ltr" ? px : (-1 * px);
this.scrollBoxObject.scrollBy(actualPx, 0);
}
else
this.scrollBoxObject.scrollBy(0, px);
]]></body>
</method>
</implementation>
@ -64,7 +141,7 @@
</binding>
<binding id="autorepeatbutton" extends="chrome://global/content/bindings/scrollbox.xml#scrollbox-base">
<content>
<content chromedir="&locale.dir;">
<xul:image class="autorepeatbutton-icon"/>
</content>
</binding>

View File

@ -293,10 +293,15 @@
}
}
// Fire an onselect event for the tabs element.
// Support both the old "select" event and the new, better-named
// "TabSelect" event.
var event = document.createEvent('Events');
event.initEvent('select', true, true);
this.dispatchEvent(event);
event = document.createEvent("Events");
event.initEvent("TabSelect", true, false);
this.dispatchEvent(event);
}
return val;
]]>

View File

@ -106,7 +106,7 @@
<xul:tab selected="true" validate="never"
onerror="this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image'));
this.removeAttribute('image');"
maxwidth="250" width="0" minwidth="30" flex="100"
maxwidth="250" width="0" minwidth="140" flex="100"
class="tabbrowser-tab" label="&untitledTab;" crop="end"/>
</xul:tabs>
</xul:hbox>
@ -1083,6 +1083,10 @@
if (!this.mTabbedMode)
this.enterTabbedMode();
// if we're adding tabs, we're past interrupt mode, ditch the owner
if (this.mCurrentTab.owner)
this.mCurrentTab.owner = null;
var t = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"tab");
@ -1095,13 +1099,17 @@
t.setAttribute("crop", "end");
t.maxWidth = 250;
t.minWidth = 30;
t.minWidth = 140;
t.width = 0;
t.setAttribute("flex", "100");
t.setAttribute("validate", "never");
t.setAttribute("onerror", "this.parentNode.parentNode.parentNode.parentNode.addToMissedIconCache(this.getAttribute('image')); this.removeAttribute('image');");
t.className = "tabbrowser-tab";
this.mTabContainer.appendChild(t);
// invalidate cache, because mTabContainer is about to change
this._browsers = null;
// If this new tab is owned by another, assert that relationship
if (aOwner !== undefined && aOwner !== null) {
t.owner = aOwner;
@ -1178,6 +1186,13 @@
b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData);
}
// Dispatch a new tab notification. We do this once we're
// entirely done, so that things are in a consistent state
// even if the event listener opens or closes tabs.
var evt = document.createEvent("Events");
evt.initEvent("TabOpen", true, false);
t.dispatchEvent(evt);
return t;
]]>
</body>
@ -1291,6 +1306,14 @@
if (ds.contentViewer && !ds.contentViewer.permitUnload())
return;
// We're committed to closing the tab now.
// Dispatch a notification.
// We dispatch it before any teardown so that event listeners can
// inspect the tab that's about to close.
var evt = document.createEvent("Events");
evt.initEvent("TabClose", true, false);
aTab.dispatchEvent(evt);
if (l == 1) {
// add a new blank tab to replace the one being closed
// (this ensures that the remaining tab is as good as new)
@ -1358,6 +1381,8 @@
// Remove the tab
this.mTabContainer.removeChild(oldTab);
// invalidate cache, because mTabContainer is about to change
this._browsers = null;
this.mPanelContainer.removeChild(oldBrowser.parentNode);
// Find the tab to select
@ -1432,8 +1457,8 @@
<body>
<![CDATA[
if (aEvent.button == 0 &&
// Only capture clicks on tabbox.xml's <spacer>
aEvent.originalTarget.localName == "spacer") {
aEvent.originalTarget.localName == "box") {
// xxx this needs to check that we're in the empty area of the tabstrip
var e = document.createEvent("Events");
e.initEvent("NewTab", true, true);
this.dispatchEvent(e);
@ -1581,30 +1606,114 @@
<parameter name="aDragSession"/>
<body>
<![CDATA[
if (aDragSession.canDrop && aDragSession.sourceNode &&
aDragSession.sourceNode.parentNode == this.mTabContainer) {
if (aDragSession.canDrop && aDragSession.sourceNode) {
// autoscroll the tab strip if we drag over the autorepeat
// buttons, even if we aren't dragging a tab, but then
// return to avoid drawing the drop indicator
var isTabDrag = (aDragSession.sourceNode.parentNode == this.mTabContainer);
var pixelsToScroll = 0;
var tabStrip = this.mTabContainer.mTabstrip;
if (aEvent.originalTarget.localName == "autorepeatbutton") {
if (aEvent.originalTarget.getAttribute("class") ==
"autorepeatbutton-up")
pixelsToScroll = tabStrip.scrollIncrement * -1;
else
pixelsToScroll = tabStrip.scrollIncrement;
tabStrip.scrollByPixels(pixelsToScroll);
}
if (!isTabDrag)
return;
var newIndex = this.getNewIndex(aEvent);
var ib = this.mTabDropIndicatorBar;
var ind = ib.firstChild;
ib.setAttribute('dragging','true');
if (window.getComputedStyle(this.parentNode, null).direction == "ltr") {
var tabStripBoxObject = tabStrip.scrollBoxObject;
var halfIndWidth = Math.floor((ind.boxObject.width + 1) / 2);
if (window.getComputedStyle(this.parentNode, null)
.direction == "ltr") {
var newMarginLeft;
var minMarginLeft = tabStripBoxObject.x - halfIndWidth;
// make sure we don't place the tab drop indicator past the
// edge, or the containing box will flex and stretch
// the tab drop indicator bar, which will flex the url bar.
// XXX todo
// just use first value if you can figure out how to get
// the tab drop indicator to crop instead of flex and stretch
// the tab drop indicator bar.
var maxMarginLeft = Math.min(
(minMarginLeft + tabStripBoxObject.width),
(ib.boxObject.x + ib.boxObject.width - ind.boxObject.width));
// if we are scrolling, put the drop indicator at the edge
// so that it doesn't jump while scrolling
if (pixelsToScroll > 0)
newMarginLeft = maxMarginLeft;
else if (pixelsToScroll < 0)
newMarginLeft = minMarginLeft;
else {
if (newIndex == this.mTabs.length) {
ind.style.marginLeft = this.mTabs[newIndex-1].boxObject.x +
this.mTabs[newIndex-1].boxObject.width - this.boxObject.x - 7 + 'px';
newMarginLeft = this.mTabs[newIndex-1].boxObject.screenX +
this.mTabs[newIndex-1].boxObject.width -
this.boxObject.screenX - halfIndWidth;
} else {
ind.style.marginLeft = this.mTabs[newIndex].boxObject.x - this.boxObject.x - 7 + 'px';
newMarginLeft = this.mTabs[newIndex].boxObject.screenX -
this.boxObject.screenX - halfIndWidth;
}
// ensure we never place the drop indicator beyond
// our limits
if (newMarginLeft < minMarginLeft)
newMarginLeft = minMarginLeft;
else if (newMarginLeft > maxMarginLeft)
newMarginLeft = maxMarginLeft;
}
ind.style.marginLeft = newMarginLeft + 'px';
} else {
var newMarginRight;
var minMarginRight = tabStripBoxObject.x - halfIndWidth;
// make sure we don't place the tab drop indicator past the
// edge, or the containing box will flex and stretch
// the tab drop indicator bar, which will flex the url bar.
// XXX todo
// just use first value if you can figure out how to get
// the tab drop indicator to crop instead of flex and stretch
// the tab drop indicator bar.
var maxMarginRight = Math.min(
(minMarginRight + tabStripBoxObject.width),
(ib.boxObject.x + ib.boxObject.width - ind.boxObject.width));
// if we are scrolling, put the drop indicator at the edge
// so that it doesn't jump while scrolling
if (pixelsToScroll > 0)
newMarginRight = maxMarginRight;
else if (pixelsToScroll < 0)
newMarginRight = minMarginRight;
else {
if (newIndex == this.mTabs.length) {
ind.style.marginRight = this.boxObject.width + this.boxObject.x -
this.mTabs[newIndex-1].boxObject.x + 'px';
newMarginRight = this.boxObject.width +
this.boxObject.screenX -
this.mTabs[newIndex-1].boxObject.screenX -
halfIndWidth;
} else {
ind.style.marginRight = this.boxObject.width + this.boxObject.x -
this.mTabs[newIndex].boxObject.x -
this.mTabs[newIndex].boxObject.width + 'px';
newMarginRight = this.boxObject.width +
this.boxObject.screenX -
this.mTabs[newIndex].boxObject.screenX -
this.mTabs[newIndex].boxObject.width -
halfIndWidth;
}
// ensure we never place the drop indicator beyond
// our limits
if (newMarginRight < minMarginRight)
newMarginRight = minMarginRight;
else if (newMarginRight > maxMarginRight)
newMarginRight = maxMarginRight;
}
ind.style.marginRight = newMarginRight + 'px';
}
}
]]>
@ -1696,15 +1805,24 @@
this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
var oldPosition = aTab._tPos;
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
this.mCurrentTab.selected = false;
this.mTabContainer.insertBefore(aTab, this.mTabContainer.childNodes[aIndex]);
// invalidate cache, because mTabContainer is about to change
this._browsers = null;
var i;
for (i = 0; i < this.mTabContainer.childNodes.length; i++) {
this.mTabContainer.childNodes[i]._tPos = i;
}
this.mCurrentTab.selected = true;
var evt = document.createEvent("UIEvents");
evt.initUIEvent("TabMove", true, false, window, oldPosition);
aTab.dispatchEvent(evt);
return aTab;
]]>
</body>
@ -1717,11 +1835,11 @@
var i;
if (window.getComputedStyle(this.parentNode, null).direction == "ltr") {
for (i = aEvent.target.localName == "tab" ? aEvent.target._tPos : 0; i < this.mTabs.length; i++)
if (aEvent.clientX < this.mTabs[i].boxObject.x + this.mTabs[i].boxObject.width / 2)
if (aEvent.screenX < this.mTabs[i].boxObject.screenX + this.mTabs[i].boxObject.width / 2)
return i;
} else {
for (i = aEvent.target.localName == "tab" ? aEvent.target._tPos : 0; i < this.mTabs.length; i++)
if (aEvent.clientX > this.mTabs[i].boxObject.x + this.mTabs[i].boxObject.width / 2)
if (aEvent.screenX > this.mTabs[i].boxObject.screenX + this.mTabs[i].boxObject.width / 2)
return i;
}
@ -2264,9 +2382,13 @@
<binding id="tabbrowser-tabs"
extends="chrome://global/content/bindings/tabbox.xml#tabs">
<content>
<xul:hbox flex="1" style="min-width: 1px;">
<xul:arrowscrollbox anonid="arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;" clicktoscroll="true">
<children includes="tab"/>
<xul:spacer class="tabs-right" flex="1"/>
</xul:arrowscrollbox>
<xul:hbox class="tabs-closebutton-box" align="center" pack="end" anonid="tabstrip-closebutton">
<xul:toolbarbutton ondblclick="event.stopPropagation();"
class="close-button tabs-closebutton"
oncommand="this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.removeCurrentTab()"/>
</xul:hbox>
</content>
<implementation>
@ -2276,20 +2398,32 @@
getService(Components.interfaces.nsIPrefBranch2);
try {
this.mTabClipWidth = pb2.getIntPref("browser.tabs.tabClipWidth");
this.mCloseButtons = pb2.getIntPref("browser.tabs.closeButtons");
}
catch (e) {
}
this._updateDisableBackgroundClose();
this.adjustTabstrip(false);
pb2.addObserver("browser.tabs.disableBackgroundClose", this._prefObserver, true);
pb2.addObserver("browser.tabs.closeButtons", this._prefObserver, true);
var self = this;
function onResize() {
self.adjustCloseButtons(1);
self.adjustTabstrip(false);
}
window.addEventListener("resize", onResize, false);
</constructor>
<field name="mTabstrip">
document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox");
</field>
<field name="mTabstripClosebutton">
document.getAnonymousElementByAttribute(this, "anonid", "tabstrip-closebutton");
</field>
<method name="_updateDisableBackgroundClose">
<body><![CDATA[
var prefs =
@ -2306,13 +2440,26 @@
}
]]></body>
</method>
<field name="_prefObserver">({
tabbox: this,
observe: function(subject, topic, data)
{
if (topic == "nsPref:changed")
this.tabbox._updateDisableBackgroundClose();
if (topic == "nsPref:changed") {
switch (data) {
case "browser.tabs.disableBackgroundClose":
this._updateDisableBackgroundClose();
break;
case "browser.tabs.closeButtons":
var pb2 =
Components.classes['@mozilla.org/preferences-service;1'].
getService(Components.interfaces.nsIPrefBranch2);
this.mCloseButtons = pb2.getIntPref("browser.tabs.closeButtons");
this.adjustTabstrip(false);
break;
}
}
},
QueryInterface : function(aIID)
@ -2325,44 +2472,97 @@
}
});
</field>
<field name="mTabClipWidth">140</field>
<method name="adjustCloseButtons">
<parameter name="aNumTabs"/>
<body><![CDATA[
// aNumTabs is the number of tabs that need to be present to cause
// the close button on the last visible tab to disappear when the
// pref for "always show the tab bar, even when only one tab is open"
// is set.
// When tabs are being removed from the tab strip, and the number of
// open tabs approaches 1 (i.e. when the number of open tabs is 2
// and one is removed), we need to set an attribute on the tabstrip
// that will cause the close button on the last item to be hidden.
// When tabs are being added to the tab strip - the number of open
// tabs is increasing (i.e. the number of open tabs is 1 and one is
// added) then we need to remove the attribute on the tab strip which
// will cause the close button to be shown on all tabs.
try {
if (this.childNodes.length == aNumTabs)
this.setAttribute("singlechild", "true");
else
this.removeAttribute("singlechild");
<field name="mTabClipWidth">130</field>
<field name="mCloseButtons">1</field>
<method name="adjustTabstrip">
<parameter name="aRemovingTab"/>
<body><![CDATA[
// modes for tabstrip
// 0 - activetab = close button on active tab only
// 1 - alltabs = close buttons on all tabs
// 2 - noclose = no close buttons at all
// 3 - closeatend = close button at the end of the tabstrip
switch (this.mCloseButtons) {
case 0:
// TabClose fires before the tab closes, so if we have two tabs
// and we're removing the tab we should go to no closebutton
if ((aRemovingTab && this.childNodes.length == 2) ||
this.childNodes.length == 1)
this.setAttribute("closebuttons", "noclose");
else
this.setAttribute("closebuttons", "activetab");
break;
case 1:
try {
// if we have only one tab, hide the closebutton
if ((aRemovingTab && this.childNodes.length == 2) ||
this.childNodes.length == 1)
this.setAttribute("closebuttons", "noclose");
else {
var width = this.firstChild.boxObject.width;
// 0 width is an invalid value and indicates an item without display,
// so ignore.
if (width > this.mTabClipWidth || width == 0)
this.removeAttribute("tiny");
this.setAttribute("closebuttons", "alltabs");
else
this.setAttribute("tiny", "true");
this.setAttribute("closebuttons", "activetab");
}
}
catch (e) {
}
break;
case 2:
case 3:
this.setAttribute("closebuttons", "noclose");
break;
}
this.mTabstripClosebutton.collapsed = this.mCloseButtons != 3;
if (aRemovingTab) {
// if we're at the end of the tabstrip, we need to ensure
// that we stay completely scrolled to the end
// this is a hack to determine if that's where we are already
var tabWidth = this.firstChild.boxObject.width;
var scrollPos = {};
this.mTabstrip.scrollBoxObject.getPosition(scrollPos, {});
if (scrollPos.value + this.mTabstrip.boxObject.width > tabWidth * (this.childNodes.length - 1))
this.mTabstrip.scrollByPixels(-1 * this.firstChild.boxObject.width);
}
]]></body>
</method>
<field name="_mPrefs">null</field>
<property name="mPrefs" readonly="true">
<getter>
<![CDATA[
if (!this._mPrefs) {
this._mPrefs =
Components.classes['@mozilla.org/preferences-service;1'].
getService(Components.interfaces.nsIPrefBranch2);
}
return this._mPrefs;
]]>
</getter>
</property>
<method name="_handleTabSelect">
<body><![CDATA[
this.mTabstrip.scrollBoxObject.ensureElementIsVisible(this.selectedItem);
]]></body>
</method>
<method name="_handleUnderflow">
<body><![CDATA[
this.mTabstrip.scrollBoxObject.scrollBy(-2400, 0);
]]></body>
</method>
</implementation>
<handlers>
<handler event="DOMNodeInserted" action="this.adjustCloseButtons(1);"/>
<handler event="DOMNodeRemoved" action="this.adjustCloseButtons(2);"/>
<handler event="TabOpen" action="this.adjustTabstrip(false);"/>
<handler event="TabClose" action="this.adjustTabstrip(true);"/>
<handler event="TabSelect" action="this._handleTabSelect()"/>
<handler event="underflow" action="this._handleUnderflow()"/>
</handlers>
</binding>

View File

@ -625,6 +625,14 @@ tab {
}
.tab-close-button {
display: none;
}
.tabbrowser-tabs:not([closebuttons="noclose"]):not([closebuttons="closeatend"]) > .tabbrowser-tab[selected="true"] > .tab-close-button {
display: -moz-box;
}
.tabbrowser-tabs[closebuttons="alltabs"] > .tabbrowser-tab > .tab-close-button {
display: -moz-box;
}
@ -632,22 +640,15 @@ tab {
display: none;
}
.tabs-closebutton-box > .tab-close-button {
display: -moz-box;
}
.tabbrowser-tabs[disablebackgroundclose="true"] > .tabbrowser-tab:not([selected="true"]) > .tab-close-button {
display: none;
}
.tabbrowser-tabs[disablebackgroundclose="true"]:not([tiny="true"]):not([singlechild="true"]) > .tabbrowser-tab:not([selected="true"]) .tab-close-button-placeholder {
display: -moz-box;
}
.tabbrowser-tabs[tiny="true"] > .tabbrowser-tab > .tab-close-button,
.tabbrowser-tabs[tiny="true"] > .tabbrowser-tab .tab-close-button-placeholder,
.tabbrowser-tabs[singlechild="true"] > .tabbrowser-tab > .tab-close-button,
.tabbrowser-tabs[singlechild="true"] > .tabbrowser-tab .tab-close-button-placeholder {
display: none;
}
.tabbrowser-tabs[tiny="true"] > .tabbrowser-tab[selected="true"] > .tab-close-button {
.tabbrowser-tabs[disablebackgroundclose="true"]:not([closebuttons="noclose"]):not([closebuttons="closeatend"]) > .tabbrowser-tab:not([selected="true"]) .tab-close-button-placeholder {
display: -moz-box;
}

View File

@ -59,9 +59,13 @@
<xul:stack>
<xul:spacer class="tabs-left"/>
</xul:stack>
<xul:hbox flex="1" style="min-width: 1px;">
<xul:arrowscrollbox anonid="arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;">
<children/>
<xul:spacer class="tabs-right" flex="1"/>
</xul:arrowscrollbox>
<xul:hbox class="tabs-closebutton-box" align="center" pack="end" anonid="tabstrip-closebutton">
<xul:toolbarbutton ondblclick="event.stopPropagation();"
class="close-button tabs-closebutton"
oncommand="this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.removeCurrentTab()"/>
</xul:hbox>
</xul:hbox>
<xul:spacer class="tabs-bottom-spacer"/>

View File

@ -5,10 +5,20 @@
*/
.autorepeatbutton-up
{
list-style-image : url("chrome://global/skin/arrow/arrow-up-sharp.gif");
list-style-image : url("chrome://global/skin/arrow/arrow-lft-sharp.gif");
}
.autorepeatbutton-down
{
list-style-image : url("chrome://global/skin/arrow/arrow-rit-sharp.gif");
}
.autorepeatbutton-up[orient="vertical"]
{
list-style-image : url("chrome://global/skin/arrow/arrow-up-sharp.gif");
}
.autorepeatbutton-down[orient="vertical"]
{
list-style-image : url("chrome://global/skin/arrow/arrow-dn-sharp.gif");
}

View File

@ -43,11 +43,6 @@ tab[selected="true"] {
-moz-padding-start: 3px;
}
.tabbrowser-tabs[tiny="true"] > .tabbrowser-tab[selected="true"],
.tabborwser-tabs[singlechild="true"] > .tabbrowser-tab[selected="true"] {
min-width: 50px; /* approximately favicon + close icon + slop for tab boundaries */
}
tab {
margin-bottom: 1px;
}

View File

@ -3,19 +3,32 @@
/*
* Autorepeatbutton
*/
.autorepeatbutton-up
.autorepeatbutton-up
{
list-style-image : url("chrome://global/skin/arrow/arrow-lft.gif");
-moz-image-region : auto; /* cut off inheritance */
}
.autorepeatbutton-down
{
list-style-image : url("chrome://global/skin/arrow/arrow-rit.gif");
-moz-image-region : auto; /* cut off inheritance */
}
.autorepeatbutton-up[orient="vertical"]
{
list-style-image : url("chrome://global/skin/arrow/arrow-up.gif");
-moz-image-region : auto; /* cut off inheritance */
}
.autorepeatbutton-down
.autorepeatbutton-down[orient="vertical"]
{
list-style-image : url("chrome://global/skin/arrow/arrow-dn.gif");
-moz-image-region : auto; /* cut off inheritance */
}
autorepeatbutton
autorepeatbutton,
autorepeatbutton[clicktoscroll="true"]:hover
{
-moz-box-align : center;
-moz-box-pack : center;
@ -27,7 +40,8 @@ autorepeatbutton
padding : 1px;
}
autorepeatbutton:hover
autorepeatbutton:hover,
autorepeatbutton:hover:active
{
margin : 1px;
border : 1px inset ThreeDFace;