Bug 658467 - Fade out tab label on overflow instead of ellipsis. r=jaws ui-r=shorlander
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -103,27 +103,37 @@
// NB: The (3) buttons are not visible, unless manually hovered,
// probably due to size reduction in this test.
tabsAccTree.children.splice(0, 0,
{
// xul:tab ("about:")
role: ROLE_PAGETAB,
children: [
{
+ // xul:text, i.e. the tab label text
+ role: ROLE_TEXT_LEAF,
+ children: []
+ },
+ {
// xul:toolbarbutton ("Close Tab")
role: ROLE_PUSHBUTTON,
children: []
}
]
},
{
// tab ("about:mozilla")
role: ROLE_PAGETAB,
children: [
{
+ // xul:text, i.e. the tab label text
+ role: ROLE_TEXT_LEAF,
+ children: []
+ },
+ {
// xul:toolbarbutton ("Close Tab")
role: ROLE_PUSHBUTTON,
children: []
}
]
},
{
// xul:toolbarbutton ("Open a new tab")
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -34,22 +34,34 @@
.tab-sharing-icon-overlay[sharing]:not([selected]),
.tab-icon-overlay[soundplaying][pinned],
.tab-icon-overlay[muted][pinned],
.tab-icon-overlay[blocked][pinned],
.tab-icon-overlay[crashed] {
display: -moz-box;
}
-.tab-label[pinned] {
+.tab-label {
+ white-space: nowrap;
+}
+
+.tab-label-container {
+ overflow: hidden;
+}
+
+.tab-label-container[pinned] {
width: 0;
- margin-left: 0 !important;
- margin-right: 0 !important;
- padding-left: 0 !important;
- padding-right: 0 !important;
+}
+
+.tab-label-container[textoverflow]:not([pinned]) {
+ mask-image: linear-gradient(to left, transparent, black 1em);
+}
+
+.tab-label-container[textoverflow]:not([pinned]):-moz-locale-dir(rtl) {
+ mask-image: linear-gradient(to right, transparent, black 1em);
}
.tab-stack {
vertical-align: top; /* for pinned tabs */
}
tabpanels {
background-color: transparent;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1433,28 +1433,26 @@
</method>
<method name="setTabTitleLoading">
<parameter name="aTab"/>
<body>
<![CDATA[
aTab.label = this.mStringBundle.getString("tabs.connecting");
- aTab.crop = "end";
- this._tabAttrModified(aTab, ["label", "crop"]);
+ this._tabAttrModified(aTab, ["label"]);
]]>
</body>
</method>
<method name="setTabTitle">
<parameter name="aTab"/>
<body>
<![CDATA[
var browser = this.getBrowserForTab(aTab);
- var crop = "end";
var title = browser.contentTitle;
if (!title) {
if (browser.currentURI.spec) {
try {
title = this.mURIFixup.createExposableURI(browser.currentURI).spec;
} catch (ex) {
title = browser.currentURI.spec;
@@ -1466,35 +1464,30 @@
// Let's try to unescape it using a character set
// in case the URI is not ASCII.
try {
var characterSet = browser.characterSet;
const textToSubURI = Components.classes["@mozilla.org/intl/texttosuburi;1"]
.getService(Components.interfaces.nsITextToSubURI);
title = textToSubURI.unEscapeNonAsciiURI(characterSet, title);
} catch (ex) { /* Do nothing. */ }
-
- crop = "center";
-
} else if (aTab.hasAttribute("customizemode")) {
let brandBundle = document.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
title = gNavigatorBundle.getFormattedString("customizeMode.tabTitle",
[ brandShortName ]);
} else // Still no title? Fall back to our untitled string.
title = this.mStringBundle.getString("tabs.emptyTabTitle");
}
- if (aTab.label == title &&
- aTab.crop == crop)
+ if (aTab.label == title)
return false;
aTab.label = title;
- aTab.crop = crop;
- this._tabAttrModified(aTab, ["label", "crop"]);
+ this._tabAttrModified(aTab, ["label"]);
if (aTab.selected)
this.updateTitlebar();
return true;
]]>
</body>
</method>
@@ -2192,17 +2185,16 @@
t.setAttribute("label", aURI);
}
if (aUserContextId) {
t.setAttribute("usercontextid", aUserContextId);
ContextualIdentityService.setTabStyle(t);
}
- t.setAttribute("crop", "end");
t.setAttribute("onerror", "this.removeAttribute('image');");
t.className = "tabbrowser-tab";
this.tabContainer._unlockTabSizing();
// When overflowing, new tabs are scrolled into view smoothly, which
// doesn't go well together with the width transition. So we skip the
// transition in that case.
@@ -5282,31 +5274,37 @@
}
return [tabStart, tabEnd];
]]></body>
</method>
</implementation>
<handlers>
<handler event="underflow" phase="capturing"><![CDATA[
+ if (event.target != this)
+ return;
+
if (event.detail == 0)
return; // Ignore vertical events
var tabs = document.getBindingParent(this);
tabs.removeAttribute("overflow");
if (tabs._lastTabClosedByMouse)
tabs._expandSpacerBy(this._scrollButtonDown.clientWidth);
for (let tab of Array.from(tabs.tabbrowser._removingTabs))
tabs.tabbrowser.removeTab(tab);
tabs._positionPinnedTabs();
]]></handler>
<handler event="overflow"><![CDATA[
+ if (event.target != this)
+ return;
+
if (event.detail == 0)
return; // Ignore vertical events
var tabs = document.getBindingParent(this);
tabs.setAttribute("overflow", "true");
tabs._positionPinnedTabs();
tabs._handleTabSelect(false);
]]></handler>
@@ -5350,17 +5348,16 @@
<implementation implements="nsIDOMEventListener, nsIObserver">
<constructor>
<![CDATA[
this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
var tab = this.firstChild;
tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle");
- tab.setAttribute("crop", "end");
tab.setAttribute("onerror", "this.removeAttribute('image');");
window.addEventListener("resize", this, false);
window.addEventListener("load", this, false);
try {
this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
} catch (ex) {
@@ -6725,20 +6722,25 @@
<xul:image xbl:inherits="sharing,selected=visuallyselected"
anonid="sharing-icon"
class="tab-sharing-icon-overlay"
role="presentation"/>
<xul:image xbl:inherits="crashed,busy,soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
anonid="overlay-icon"
class="tab-icon-overlay"
role="presentation"/>
- <xul:label flex="1"
- xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected=visuallyselected,attention"
- class="tab-text tab-label"
- role="presentation"/>
+ <xul:hbox class="tab-label-container"
+ xbl:inherits="pinned,selected=visuallyselected"
+ onoverflow="this.setAttribute('textoverflow', 'true');"
+ onunderflow="this.removeAttribute('textoverflow');"
+ flex="1">
+ <xul:label class="tab-text tab-label"
+ xbl:inherits="xbl:text=label,accesskey,fadein,pinned,selected=visuallyselected,attention"
+ role="presentation"/>
+ </xul:hbox>
<xul:image xbl:inherits="soundplaying,soundplaying-scheduledremoval,pinned,muted,blocked,selected=visuallyselected"
anonid="soundplaying-icon"
class="tab-icon-sound"
role="presentation"/>
<xul:toolbarbutton anonid="close-button"
xbl:inherits="fadein,pinned,selected=visuallyselected"
class="tab-close-button close-icon"/>
</xul:hbox>
@@ -7107,17 +7109,17 @@
]]></body>
</method>
<method name="_setMenuitemAttributes">
<parameter name="aMenuitem"/>
<parameter name="aTab"/>
<body><![CDATA[
aMenuitem.setAttribute("label", aTab.label);
- aMenuitem.setAttribute("crop", aTab.getAttribute("crop"));
+ aMenuitem.setAttribute("crop", "end");
if (aTab.hasAttribute("busy")) {
aMenuitem.setAttribute("busy", aTab.getAttribute("busy"));
aMenuitem.removeAttribute("image");
} else {
aMenuitem.setAttribute("image", aTab.getAttribute("image"));
aMenuitem.removeAttribute("busy");
}
--- a/browser/base/content/test/general/browser_overflowScroll.js
+++ b/browser/base/content/test/general/browser_overflowScroll.js
@@ -32,17 +32,18 @@ function doTest() {
while (tabs.length < tabCountForOverflow)
gBrowser.addTab("about:blank", {skipAnimation: true});
gBrowser.pinTab(tabs[0]);
tabstrip.addEventListener("overflow", runOverflowTests, false);
}
function runOverflowTests(aEvent) {
- if (aEvent.detail != 1)
+ if (aEvent.detail != 1 ||
+ aEvent.target != tabstrip)
return;
tabstrip.removeEventListener("overflow", runOverflowTests, false);
var upButton = tabstrip._scrollButtonUp;
var downButton = tabstrip._scrollButtonDown;
var element;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2445,16 +2445,17 @@ toolbarbutton.chevron > .toolbarbutton-m
margin: 0;
}
%include ../shared/tabs.inc.css
.tab-label {
margin-top: 1px;
margin-bottom: 0;
+ -moz-box-flex: 1;
text-align: center;
}
@media (-moz-mac-yosemite-theme) {
/* image preloading hack from shared/tabs.inc.css */
#tabbrowser-tabs::before {
background-image:
url(chrome://browser/skin/yosemite/tab-selected-end-inactive.svg),
@@ -2544,17 +2545,17 @@ toolbarbutton.chevron > .toolbarbutton-m
/*
* Force the overlay to create a new stacking context so it always appears on
* top of the icon.
*/
.tab-icon-overlay {
opacity: 0.9999;
}
-.tab-label:not([selected="true"]) {
+.tab-label-container:not([selected="true"]) {
opacity: .7;
}
.tabbrowser-tab,
.tabs-newtab-button {
font: message-box;
border: none;
}
@@ -2570,17 +2571,17 @@ toolbarbutton.chevron > .toolbarbutton-m
}
.tabs-newtab-button > .toolbarbutton-icon {
-moz-box-align: center;
border: solid transparent;
border-width: 0 11px;
}
-.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label:not([pinned]),
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label-container:not([pinned]),
.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-icon-image[pinned],
.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-throbber[pinned] {
box-shadow: @focusRingShadow@;
}
#TabsToolbar {
-moz-appearance: none;
/* overlap the nav-bar's top border */
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -186,17 +186,17 @@
}
.tab-label {
margin-inline-end: 0;
margin-inline-start: 0;
}
.tab-close-button {
- margin-inline-start: 4px;
+ margin-inline-start: 2px;
margin-inline-end: -2px;
padding: 0;
}
.tab-icon-sound {
margin-inline-start: 4px;
width: 16px;
height: 16px;