--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1428,34 +1428,59 @@
}
this._tabAttrModified(tab, ["sharing"]);
if (aBrowser == this.mCurrentBrowser)
gIdentityHandler.updateSharingIndicator();
]]></body>
</method>
-
<!-- TODO: remove after 57, once we know add-ons can no longer use it. -->
<method name="setTabTitleLoading">
<parameter name="aTab"/>
<body/>
</method>
<method name="setInitialTabTitle">
<parameter name="aTab"/>
<parameter name="aTitle"/>
<parameter name="aOptions"/>
<body><![CDATA[
- if (aTitle) {
+ // If we don't have the content title yet, aTitle is a URI. Set its hostname
+ // as the label so that the tab isn't empty while the content is loading.
+ const label = aOptions && aOptions.isContentTitle
+ ? aTitle
+ : getHostnameWithoutWWW(aTitle, this.mURIFixup);
+
+ if (label) {
// Don't replace the set label with the empty tab label or the URL
// while the tab is loading.
aTab._suppressTransientPlaceholderLabel = true;
- this._setTabLabel(aTab, aTitle, aOptions);
+ this._setTabLabel(aTab, label, aOptions);
+ }
+
+ function getHostnameWithoutWWW(uri, URIFixup) {
+ // about: pages don't have hostnames, so we can bail early here.
+ if (uri.startsWith("about:")) {
+ return uri;
+ }
+
+ // Some tests pass in values that are not valid URLs, such as
+ // "example.com" with no scheme. Just show whatever was passed in
+ // until we know the page's actual title.
+ let hostname;
+ try {
+ const fixedURI = URIFixup.createFixupURI(uri, URIFixup.FIXUP_FLAG_NONE);
+ hostname = fixedURI.host;
+ } catch (e) {
+ return uri;
+ }
+
+ return hostname.startsWith("www.") ? hostname.slice(4) : hostname;
}
]]></body>
</method>
<method name="setTabTitle">
<parameter name="aTab"/>
<body>
<![CDATA[
@@ -2388,17 +2413,17 @@
}
var uriIsAboutBlank = aURI == "about:blank";
if (!aNoInitialLabel) {
if (isBlankPageURL(aURI)) {
t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle"));
} else {
- // Set URL as label so that the tab isn't empty initially.
+ // Set hostname as label so that the tab isn't empty initially.
this.setInitialTabTitle(t, aURI, { beforeTabOpen: true });
}
}
if (aIsPrerendered) {
t.setAttribute("hidden", "true");
}
--- a/browser/components/sessionstore/test/browser_tab_label_during_restore.js
+++ b/browser/components/sessionstore/test/browser_tab_label_during_restore.js
@@ -1,24 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
/**
* Test that we don't do unnecessary tab label changes while restoring a tab.
*/
add_task(async function() {
await SpecialPowers.pushPrefEnv({
"set": [
["browser.sessionstore.restore_on_demand", true],
["browser.sessionstore.restore_tabs_lazily", true],
]
});
+
const BACKUP_STATE = SessionStore.getBrowserState();
- const TEST_URL = "http://example.com/";
+ const TEST_URL = "http://www.example.com/";
+ const ABOUT_ROBOTS_URI = "about:robots";
+ const ABOUT_ROBOTS_TITLE = "Gort! Klaatu barada nikto!";
function observeLabelChanges(tab) {
info("observing tab label changes. initial label: " + tab.label);
let labelChangeCount = 0;
function TabAttrModifiedListener(event) {
if (event.detail.changed.some(attr => { return attr == "label" })) {
info("tab label change: " + tab.label);
labelChangeCount++;
@@ -32,58 +37,78 @@ add_task(async function() {
}
info("setting test browser state");
let browserLoadedPromise = BrowserTestUtils.firstBrowserLoaded(window, false);
await promiseBrowserState({
windows: [{
tabs: [
{ entries: [{ url: TEST_URL }] },
+ { entries: [{ url: ABOUT_ROBOTS_URI }] },
{ entries: [{ url: TEST_URL }] },
]
}]
});
- let [firstTab, secondTab] = gBrowser.tabs;
+ let [firstTab, secondTab, thirdTab] = gBrowser.tabs;
is(gBrowser.selectedTab, firstTab, "first tab is selected");
await browserLoadedPromise;
const CONTENT_TITLE = firstTab.linkedBrowser.contentTitle;
is(firstTab.linkedBrowser.currentURI.spec, TEST_URL, "correct URL loaded in first tab");
is(typeof CONTENT_TITLE, "string", "content title is a string");
isnot(CONTENT_TITLE.length, 0, "content title isn't empty");
isnot(CONTENT_TITLE, TEST_URL, "content title is different from the URL");
is(firstTab.label, CONTENT_TITLE, "first tab displays content title");
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
ok(secondTab.hasAttribute("pending"), "second tab is pending");
- is(secondTab.label, TEST_URL, "second tab displays URL as its title");
+ // The fix for bug 1364127 caused about: pages' initial tab titles to show
+ // their about: URIs until their actual page titles are known, e.g.
+ // "about:addons" -> "Add-ons Manager". This is bug 1371896. Previously,
+ // about: pages' initial tab titles were blank until the page title was known.
+ is(secondTab.label, ABOUT_ROBOTS_URI, "second tab displays URI as its initial title");
+ ok(thirdTab.hasAttribute("pending"), "third tab is pending");
+ is(thirdTab.label, "example.com", "third tab's initial tab title is its hostname without 'www.'");
info("selecting the second tab");
let checkLabelChangeCount = observeLabelChanges(secondTab);
- browserLoadedPromise = BrowserTestUtils.browserLoaded(secondTab.linkedBrowser, false, TEST_URL);
+ browserLoadedPromise = BrowserTestUtils.browserLoaded(secondTab.linkedBrowser, false, ABOUT_ROBOTS_URI);
gBrowser.selectedTab = secondTab;
await browserLoadedPromise;
ok(!secondTab.hasAttribute("pending"), "second tab isn't pending anymore");
- is(secondTab.label, CONTENT_TITLE, "second tab displays content title");
+ is(secondTab.label, ABOUT_ROBOTS_TITLE, "second tab displays content title");
+ ok(document.title.startsWith(ABOUT_ROBOTS_TITLE), "title bar displays content title");
+ checkLabelChangeCount(1); // ABOUT_ROBOTS_URI -> ABOUT_ROBOTS_TITLE
+
+ info("selecting the third tab");
+ checkLabelChangeCount = observeLabelChanges(thirdTab);
+ browserLoadedPromise = BrowserTestUtils.browserLoaded(thirdTab.linkedBrowser, false, TEST_URL);
+ gBrowser.selectedTab = thirdTab;
+ await browserLoadedPromise;
+ ok(!thirdTab.hasAttribute("pending"), "third tab isn't pending anymore");
+ is(thirdTab.label, CONTENT_TITLE, "third tab displays content title");
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
- checkLabelChangeCount(1);
+ checkLabelChangeCount(1); // TEST_URL -> CONTENT_TITLE
info("restoring the modified browser state");
await TabStateFlusher.flushWindow(window);
await promiseBrowserState(SessionStore.getBrowserState());
- [firstTab, secondTab] = gBrowser.tabs;
- is(secondTab, gBrowser.selectedTab, "second tab is selected after restoring");
+ [firstTab, secondTab, thirdTab] = gBrowser.tabs;
+ is(thirdTab, gBrowser.selectedTab, "third tab is selected after restoring");
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
ok(firstTab.hasAttribute("pending"), "first tab is pending after restoring");
is(firstTab.label, CONTENT_TITLE, "first tab displays content title in pending state");
+ ok(secondTab.hasAttribute("pending"), "second tab is pending after restoring");
+ is(secondTab.label, ABOUT_ROBOTS_TITLE, "second tab displays content title");
+ ok(!thirdTab.hasAttribute("pending"), "third tab is not pending after restoring");
+ is(thirdTab.label, CONTENT_TITLE, "third tab displays content title in pending state");
info("selecting the first tab");
checkLabelChangeCount = observeLabelChanges(firstTab);
let tabContentRestored = TestUtils.topicObserved("sessionstore-debug-tab-restored");
gBrowser.selectedTab = firstTab;
ok(document.title.startsWith(CONTENT_TITLE), "title bar displays content title");
await tabContentRestored;
ok(!firstTab.hasAttribute("pending"), "first tab isn't pending anymore");
checkLabelChangeCount(0);
is(firstTab.label, CONTENT_TITLE, "first tab displays content title after restoring content");
await promiseBrowserState(BACKUP_STATE);
});
-