mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
Bug 1899336
- Position pinned tabs and new tab button for vertical tabs mode r=dao,sidebar-reviewers,desktop-theme-reviewers,tabbrowser-reviewers,kcochrane
* Create a new container to house pinned tabs, new tab button and non-pinned tabs * Create new pinned tabs container to apply grid layout and overflow scrolling * Update test coverage for pinned tabs for both horizontal and vertical tabs Differential Revision: https://phabricator.services.mozilla.com/D215482
This commit is contained in:
parent
78c45e20c4
commit
d4f7db068b
@ -5,8 +5,7 @@
|
||||
<hbox flex="1" id="browser">
|
||||
<box context="sidebar-context-menu" id="sidebar-main" hidden="true">
|
||||
<html:sidebar-main flex="1">
|
||||
<html:div id="vertical-tabs" slot="tabstrip">
|
||||
</html:div>
|
||||
<html:div id="vertical-tabs" slot="tabstrip"></html:div>
|
||||
</html:sidebar-main>
|
||||
</box>
|
||||
<vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
|
||||
|
@ -5002,6 +5002,7 @@ const nodeToTooltipMap = {
|
||||
"appMenu-zoomReduce-button2": "zoomReduce-button.tooltip",
|
||||
"reader-mode-button": "reader-mode-button.tooltip",
|
||||
"reader-mode-button-icon": "reader-mode-button.tooltip",
|
||||
"vertical-tabs-newtab-button": "newTabButton.tooltip",
|
||||
};
|
||||
const nodeToShortcutMap = {
|
||||
"bookmarks-menu-button": "manBookmarkKb",
|
||||
@ -5021,6 +5022,7 @@ const nodeToShortcutMap = {
|
||||
"appMenu-zoomReduce-button2": "key_fullZoomReduce",
|
||||
"reader-mode-button": "key_toggleReaderMode",
|
||||
"reader-mode-button-icon": "key_toggleReaderMode",
|
||||
"vertical-tabs-newtab-button": "key_newNavigatorTab",
|
||||
};
|
||||
|
||||
const gDynamicTooltipCache = new Map();
|
||||
|
@ -50,12 +50,22 @@
|
||||
aria-multiselectable="true"
|
||||
setfocus="false"
|
||||
tooltip="tabbrowser-tab-tooltip"
|
||||
orient="horizontal"
|
||||
stopwatchid="FX_TAB_CLICK_MS">
|
||||
<hbox class="tab-drop-indicator" hidden="true"/>
|
||||
# If the name (tabbrowser-arrowscrollbox) or structure of this changes
|
||||
# significantly, there is an optimization in
|
||||
# DisplayPortUtils::MaybeCreateDisplayPortInFirstScrollFrameEncountered based
|
||||
# the current structure that we may want to revisit.
|
||||
<html:div id="vertical-pinned-tabs-container"></html:div>
|
||||
<html:div id="newtab-button-container">
|
||||
<toolbarbutton id="vertical-tabs-newtab-button"
|
||||
class="toolbarbutton-1"
|
||||
command="cmd_newNavigatorTab"
|
||||
onclick="gBrowser.handleNewTabMiddleClick(this, event);"
|
||||
tooltip="dynamic-shortcut-tooltip"
|
||||
data-l10n-id="tabs-toolbar-new-tab"/>
|
||||
</html:div>
|
||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" style="min-width: 1px;" clicktoscroll="true" scrolledtostart="true" scrolledtoend="true">
|
||||
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="" fadein=""/>
|
||||
<hbox id="tabbrowser-arrowscrollbox-periphery">
|
||||
|
@ -124,6 +124,7 @@
|
||||
border-radius: 2px;
|
||||
margin: -3px 2px 0;
|
||||
|
||||
#vertical-pinned-tabs-container &,
|
||||
#tabbrowser-tabs[orient="vertical"] & {
|
||||
height: 100%;
|
||||
margin: 0 -2px;
|
||||
|
@ -245,6 +245,8 @@ skip-if = ["true"] #Bug 1455602
|
||||
|
||||
["browser_restore_tabless_window.js"]
|
||||
|
||||
["browser_restore_verticalPinnedTabs.js"]
|
||||
|
||||
["browser_restored_window_features.js"]
|
||||
|
||||
["browser_revive_crashed_bg_tabs.js"]
|
||||
|
@ -0,0 +1,72 @@
|
||||
add_setup(() =>
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["sidebar.revamp", true],
|
||||
["sidebar.verticalTabs", true],
|
||||
],
|
||||
})
|
||||
);
|
||||
registerCleanupFunction(() => SpecialPowers.popPrefEnv());
|
||||
|
||||
let newState = {
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [{ url: "https://example.com", triggeringPrincipal_base64 }],
|
||||
pinned: "true",
|
||||
hidden: "false",
|
||||
},
|
||||
{
|
||||
entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }],
|
||||
pinned: "true",
|
||||
hidden: "false",
|
||||
},
|
||||
{
|
||||
entries: [{ url: "about:home", triggeringPrincipal_base64 }],
|
||||
hidden: "false",
|
||||
},
|
||||
{
|
||||
entries: [
|
||||
{ url: "https://www.example.net/", triggeringPrincipal_base64 },
|
||||
],
|
||||
hidden: "false",
|
||||
pinned: "true",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
add_task(async function test_pinned_tabs_restored_position() {
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
await setWindowState(win, newState, true);
|
||||
|
||||
const { document } = win;
|
||||
const sidebar = document.querySelector("sidebar-main");
|
||||
ok(sidebar, "Sidebar is shown.");
|
||||
|
||||
let tabStrip = document.getElementById("tabbrowser-tabs");
|
||||
let verticalTabs = document.querySelector("#vertical-tabs");
|
||||
let verticalPinnedTabsContainer = document.querySelector(
|
||||
"#vertical-pinned-tabs-container"
|
||||
);
|
||||
|
||||
ok(BrowserTestUtils.isVisible(verticalTabs), "Vertical tabs slot is visible");
|
||||
is(
|
||||
tabStrip.parentNode,
|
||||
verticalTabs,
|
||||
"Tabstrip is slotted into the sidebar vertical tabs container"
|
||||
);
|
||||
ok(
|
||||
BrowserTestUtils.isVisible(verticalPinnedTabsContainer),
|
||||
"Vertical pinned tabs container is visible"
|
||||
);
|
||||
is(
|
||||
verticalPinnedTabsContainer.children.length,
|
||||
win.gBrowser._numPinnedTabs,
|
||||
"Three tabs are in the vertical pinned tabs container"
|
||||
);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
@ -246,7 +246,11 @@ var SidebarController = {
|
||||
this._switcherPanel = document.getElementById("sidebarMenu-popup");
|
||||
this._switcherTarget = document.getElementById("sidebar-switcher-target");
|
||||
this._switcherArrow = document.getElementById("sidebar-switcher-arrow");
|
||||
let newTabButton = document.getElementById("vertical-tabs-newtab-button");
|
||||
|
||||
newTabButton.addEventListener("command", event => {
|
||||
BrowserCommands.openTab({ event });
|
||||
});
|
||||
if (
|
||||
Services.prefs.getBoolPref(
|
||||
"browser.tabs.allow_transparent_browser",
|
||||
@ -1198,12 +1202,10 @@ var SidebarController = {
|
||||
if (this.sidebarVerticalTabsEnabled) {
|
||||
arrowScrollbox.setAttribute("orient", "vertical");
|
||||
tabStrip.setAttribute("orient", "vertical");
|
||||
tabStrip.removeAttribute("overflow");
|
||||
tabStrip._positionPinnedTabs();
|
||||
verticalTabs.append(tabStrip);
|
||||
} else {
|
||||
arrowScrollbox.setAttribute("orient", "horizontal");
|
||||
tabStrip.removeAttribute("orient");
|
||||
tabStrip.setAttribute("orient", "horizontal");
|
||||
|
||||
// make sure we put the tabstrip back in its original position in the TabsToolbar
|
||||
if (tabstripPlacement < tabsToolbarWidgets.length) {
|
||||
@ -1219,7 +1221,7 @@ var SidebarController = {
|
||||
.append(tabStrip);
|
||||
}
|
||||
}
|
||||
verticalTabs.toggleAttribute("activated", this.sidebarVerticalTabsEnabled);
|
||||
verticalTabs.toggleAttribute("visible", this.sidebarVerticalTabsEnabled);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -4,13 +4,14 @@
|
||||
|
||||
.wrapper {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-rows: auto min-content min-content;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
min-width: 50px;
|
||||
padding-inline-start: var(--space-medium);
|
||||
padding: var(--space-small);
|
||||
padding-inline-end: 0;
|
||||
border-inline-end: 1px solid var(--chrome-content-separator-color);
|
||||
background-color: var(--sidebar-background-color);
|
||||
background-color: var(--toolbar-bgcolor);
|
||||
color: var(--sidebar-text-color);
|
||||
:host([positionend]) & {
|
||||
border-inline-start: 1px solid var(--chrome-content-separator-color);
|
||||
@ -21,8 +22,8 @@
|
||||
.actions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: end;
|
||||
gap: var(--space-xsmall);
|
||||
justify-content: center;
|
||||
padding-inline-start: var(--space-xsmall);
|
||||
}
|
||||
|
||||
.expanded-button {
|
||||
@ -34,3 +35,11 @@
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.tools-and-extensions {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.bottom-actions {
|
||||
align-self: end;
|
||||
}
|
||||
|
@ -346,6 +346,12 @@
|
||||
return (this.tabpanels = document.getElementById("tabbrowser-tabpanels"));
|
||||
},
|
||||
|
||||
get verticalPinnedTabsContainer() {
|
||||
return (this.verticalPinnedTabsContainer = document.getElementById(
|
||||
"vertical-pinned-tabs-container"
|
||||
));
|
||||
},
|
||||
|
||||
addEventListener(...args) {
|
||||
this.tabpanels.addEventListener(...args);
|
||||
},
|
||||
@ -841,7 +847,15 @@
|
||||
}
|
||||
|
||||
this.showTab(aTab);
|
||||
this.moveTabTo(aTab, this._numPinnedTabs);
|
||||
if (this.tabContainer.inVerticalTabsMode) {
|
||||
let wasFocused = document.activeElement == this.selectedTab;
|
||||
let oldPosition = aTab._tPos;
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
this.verticalPinnedTabsContainer.appendChild(aTab);
|
||||
this._updateAfterMoveTabTo(aTab, oldPosition, wasFocused);
|
||||
} else {
|
||||
this.moveTabTo(aTab, this._numPinnedTabs);
|
||||
}
|
||||
aTab.setAttribute("pinned", "true");
|
||||
this._updateTabBarForPinnedTabs();
|
||||
this._notifyPinnedStatus(aTab);
|
||||
@ -852,8 +866,20 @@
|
||||
return;
|
||||
}
|
||||
|
||||
this.moveTabTo(aTab, this._numPinnedTabs - 1);
|
||||
aTab.removeAttribute("pinned");
|
||||
if (this.tabContainer.inVerticalTabsMode) {
|
||||
let wasFocused = document.activeElement == this.selectedTab;
|
||||
let oldPosition = aTab._tPos;
|
||||
// we remove this attribute first, so that allTabs represents
|
||||
// the moving of a tab from the vertical pinned tabs container
|
||||
// and back into arrowscrollbox.
|
||||
aTab.removeAttribute("pinned");
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
this.tabContainer.arrowScrollbox.prepend(aTab);
|
||||
this._updateAfterMoveTabTo(aTab, oldPosition, wasFocused);
|
||||
} else {
|
||||
this.moveTabTo(aTab, this._numPinnedTabs - 1);
|
||||
aTab.removeAttribute("pinned");
|
||||
}
|
||||
aTab.style.marginInlineStart = "";
|
||||
aTab._pinnedUnscrollable = false;
|
||||
this._updateTabBarForPinnedTabs();
|
||||
@ -5286,11 +5312,24 @@
|
||||
|
||||
let wasFocused = document.activeElement == this.selectedTab;
|
||||
|
||||
aIndex = aIndex < aTab._tPos ? aIndex : aIndex + 1;
|
||||
let neighbor = this.tabs[aIndex];
|
||||
if (aIndex < aTab._tPos) {
|
||||
neighbor.before(aTab);
|
||||
} else if (!neighbor) {
|
||||
// Put the tab after the neighbor, as once we remove the tab from its current position,
|
||||
// the indexing of the tabs will shift.
|
||||
aTab.parentElement.append(aTab);
|
||||
} else {
|
||||
neighbor.after(aTab);
|
||||
}
|
||||
|
||||
let neighbor = this.tabs[aIndex] || null;
|
||||
// We want to clear _allTabs after moving nodes because the order of
|
||||
// vertical tabs may have changed.
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
this.tabContainer.insertBefore(aTab, neighbor);
|
||||
this._updateAfterMoveTabTo(aTab, oldPosition, wasFocused);
|
||||
},
|
||||
|
||||
_updateAfterMoveTabTo(aTab, oldPosition, wasFocused = null) {
|
||||
this._updateTabsAfterInsert();
|
||||
|
||||
if (wasFocused) {
|
||||
@ -5302,7 +5341,11 @@
|
||||
if (aTab.pinned) {
|
||||
this.tabContainer._positionPinnedTabs();
|
||||
}
|
||||
|
||||
// Pinning and unpinning vertical tabs bypasses moveTabTo,
|
||||
// so we still want to check whether its worth dispatching an event
|
||||
if (oldPosition == aTab._tPos) {
|
||||
return;
|
||||
}
|
||||
var evt = document.createEvent("UIEvents");
|
||||
evt.initUIEvent("TabMove", true, false, window, oldPosition);
|
||||
aTab.dispatchEvent(evt);
|
||||
|
@ -12,6 +12,7 @@
|
||||
const TAB_PREVIEW_PREF = "browser.tabs.hoverPreview.enabled";
|
||||
|
||||
class MozTabbrowserTabs extends MozElements.TabsBase {
|
||||
static observedAttributes = ["orient"];
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@ -143,6 +144,19 @@
|
||||
this._previewPanel = null;
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (name != "orient") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldValue == "vertical" && newValue == "horizontal") {
|
||||
this._resetVerticalPinnedTabs();
|
||||
}
|
||||
this._positionPinnedTabs();
|
||||
|
||||
super.attributeChangedCallback(name, oldValue, newValue);
|
||||
}
|
||||
|
||||
on_TabSelect() {
|
||||
this._handleTabSelect();
|
||||
}
|
||||
@ -1130,16 +1144,26 @@
|
||||
if (this._allTabs) {
|
||||
return this._allTabs;
|
||||
}
|
||||
let verticalPinnedTabsContainer = document.getElementById(
|
||||
"vertical-pinned-tabs-container"
|
||||
);
|
||||
let children = Array.from(this.arrowScrollbox.children);
|
||||
// remove arrowScrollbox periphery element
|
||||
children.pop();
|
||||
this._allTabs = children;
|
||||
return children;
|
||||
|
||||
let allChildren = [...verticalPinnedTabsContainer.children, ...children];
|
||||
this._allTabs = allChildren;
|
||||
return allChildren;
|
||||
}
|
||||
|
||||
get previewPanel() {
|
||||
return this._previewPanel;
|
||||
}
|
||||
|
||||
get verticalMode() {
|
||||
return this.getAttribute("orient") == "vertical";
|
||||
}
|
||||
|
||||
_getVisibleTabs() {
|
||||
if (!this._visibleTabs) {
|
||||
this._visibleTabs = Array.prototype.filter.call(
|
||||
@ -1173,7 +1197,8 @@
|
||||
// We have a container for non-tab elements at the end of the scrollbox.
|
||||
node = arrowScrollbox.lastChild;
|
||||
}
|
||||
return arrowScrollbox.insertBefore(tab, node);
|
||||
|
||||
return node.before(tab);
|
||||
}
|
||||
|
||||
set _tabMinWidth(val) {
|
||||
@ -1494,18 +1519,57 @@
|
||||
this._handleTabSelect(true);
|
||||
}
|
||||
|
||||
_updateVerticalPinnedTabs() {
|
||||
// Move pinned tabs to another container when the tabstrip is toggled to vertical
|
||||
// and when session restore code calls _positionPinnedTabs; update styling whenever
|
||||
// the number of pinned tabs changes.
|
||||
let verticalTabsContainer = document.getElementById(
|
||||
"vertical-pinned-tabs-container"
|
||||
);
|
||||
let newTabButton = document.getElementById("newtab-button-container");
|
||||
let numPinned = gBrowser._numPinnedTabs;
|
||||
|
||||
if (gBrowser._numPinnedTabs !== verticalTabsContainer.children.length) {
|
||||
let tabs = this._getVisibleTabs();
|
||||
for (let i = 0; i < numPinned; i++) {
|
||||
tabs[i].style.marginInlineStart = "";
|
||||
verticalTabsContainer.appendChild(tabs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
newTabButton.toggleAttribute("showborder", gBrowser._numPinnedTabs !== 0);
|
||||
this.style.removeProperty("--tab-overflow-pinned-tabs-width");
|
||||
}
|
||||
|
||||
_resetVerticalPinnedTabs() {
|
||||
let verticalTabsContainer = document.getElementById(
|
||||
"vertical-pinned-tabs-container"
|
||||
);
|
||||
|
||||
if (!verticalTabsContainer.children.length) {
|
||||
return;
|
||||
}
|
||||
for (const child of Array.from(
|
||||
verticalTabsContainer.children
|
||||
).reverse()) {
|
||||
this.arrowScrollbox.prepend(child);
|
||||
}
|
||||
}
|
||||
|
||||
_positionPinnedTabs() {
|
||||
let tabs = this._getVisibleTabs();
|
||||
let numPinned = gBrowser._numPinnedTabs;
|
||||
let doPosition =
|
||||
let absPositionHorizontalTabs =
|
||||
this.hasAttribute("overflow") &&
|
||||
tabs.length > numPinned &&
|
||||
numPinned > 0;
|
||||
|
||||
this.toggleAttribute("haspinnedtabs", !!numPinned);
|
||||
this.toggleAttribute("positionpinnedtabs", doPosition);
|
||||
this.toggleAttribute("positionpinnedtabs", absPositionHorizontalTabs);
|
||||
|
||||
if (doPosition) {
|
||||
if (this.verticalMode) {
|
||||
this._updateVerticalPinnedTabs();
|
||||
} else if (absPositionHorizontalTabs) {
|
||||
let layoutData = this._pinnedTabsLayoutCache;
|
||||
let uiDensity = document.documentElement.getAttribute("uidensity");
|
||||
if (!layoutData || layoutData.uiDensity != uiDensity) {
|
||||
|
@ -1,7 +1,17 @@
|
||||
add_setup(() =>
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["sidebar.revamp", true],
|
||||
["sidebar.verticalTabs", false],
|
||||
],
|
||||
})
|
||||
);
|
||||
registerCleanupFunction(() => SpecialPowers.popPrefEnv());
|
||||
var tabs;
|
||||
var tabbrowser;
|
||||
|
||||
function index(tab) {
|
||||
return Array.prototype.indexOf.call(gBrowser.tabs, tab);
|
||||
return Array.prototype.indexOf.call(tabbrowser.tabs, tab);
|
||||
}
|
||||
|
||||
function indexTest(tab, expectedIndex, msg) {
|
||||
@ -24,7 +34,7 @@ function PinUnpinHandler(tab, eventName) {
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
gBrowser.tabContainer.addEventListener(
|
||||
tabbrowser.tabContainer.addEventListener(
|
||||
eventName,
|
||||
function (e) {
|
||||
if (e.originalTarget == tab) {
|
||||
@ -35,12 +45,15 @@ function PinUnpinHandler(tab, eventName) {
|
||||
);
|
||||
}
|
||||
|
||||
function test() {
|
||||
add_task(async function test_pinned_horizontal_tabs() {
|
||||
const win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
tabbrowser = win.gBrowser;
|
||||
|
||||
tabs = [
|
||||
gBrowser.selectedTab,
|
||||
BrowserTestUtils.addTab(gBrowser),
|
||||
BrowserTestUtils.addTab(gBrowser),
|
||||
BrowserTestUtils.addTab(gBrowser),
|
||||
tabbrowser.selectedTab,
|
||||
BrowserTestUtils.addTab(tabbrowser, "about:blank"),
|
||||
BrowserTestUtils.addTab(tabbrowser, "about:mozilla"),
|
||||
BrowserTestUtils.addTab(tabbrowser, "about:home"),
|
||||
];
|
||||
indexTest(0, 0);
|
||||
indexTest(1, 1);
|
||||
@ -49,10 +62,10 @@ function test() {
|
||||
|
||||
// Discard one of the test tabs to verify that pinning/unpinning
|
||||
// discarded tabs does not regress (regression test for Bug 1852391).
|
||||
gBrowser.discardBrowser(tabs[1], true);
|
||||
tabbrowser.discardBrowser(tabs[1], true);
|
||||
|
||||
var eh = new PinUnpinHandler(tabs[3], "TabPinned");
|
||||
gBrowser.pinTab(tabs[3]);
|
||||
tabbrowser.pinTab(tabs[3]);
|
||||
is(eh.eventCount, 2, "TabPinned event should be fired");
|
||||
indexTest(0, 1);
|
||||
indexTest(1, 2);
|
||||
@ -60,21 +73,21 @@ function test() {
|
||||
indexTest(3, 0);
|
||||
|
||||
eh = new PinUnpinHandler(tabs[1], "TabPinned");
|
||||
gBrowser.pinTab(tabs[1]);
|
||||
tabbrowser.pinTab(tabs[1]);
|
||||
is(eh.eventCount, 2, "TabPinned event should be fired");
|
||||
indexTest(0, 2);
|
||||
indexTest(1, 1);
|
||||
indexTest(2, 3);
|
||||
indexTest(3, 0);
|
||||
|
||||
gBrowser.moveTabTo(tabs[3], 3);
|
||||
tabbrowser.moveTabTo(tabs[3], 3);
|
||||
indexTest(3, 1, "shouldn't be able to mix a pinned tab into normal tabs");
|
||||
|
||||
gBrowser.moveTabTo(tabs[2], 0);
|
||||
tabbrowser.moveTabTo(tabs[2], 0);
|
||||
indexTest(2, 2, "shouldn't be able to mix a normal tab into pinned tabs");
|
||||
|
||||
eh = new PinUnpinHandler(tabs[1], "TabUnpinned");
|
||||
gBrowser.unpinTab(tabs[1]);
|
||||
tabbrowser.unpinTab(tabs[1]);
|
||||
is(eh.eventCount, 2, "TabUnpinned event should be fired");
|
||||
indexTest(
|
||||
1,
|
||||
@ -82,16 +95,111 @@ function test() {
|
||||
"unpinning a tab should move a tab to the start of normal tabs"
|
||||
);
|
||||
|
||||
eh = new PinUnpinHandler(tabs[3], "TabUnpinned");
|
||||
gBrowser.unpinTab(tabs[3]);
|
||||
is(eh.eventCount, 2, "TabUnpinned event should be fired");
|
||||
const { document } = win;
|
||||
const sidebar = document.querySelector("sidebar-main");
|
||||
ok(sidebar, "Sidebar is shown.");
|
||||
|
||||
let tabStrip = tabbrowser.tabContainer;
|
||||
let verticalTabs = document.querySelector("#vertical-tabs");
|
||||
let verticalPinnedTabsContainer = document.querySelector(
|
||||
"#vertical-pinned-tabs-container"
|
||||
);
|
||||
|
||||
is(tabbrowser._numPinnedTabs, 1, "One tab is pinned in horizontal tabstrip");
|
||||
ok(tabs[3].pinned, "Third tab is pinned");
|
||||
|
||||
// flip the pref to move the tabstrip into the sidebar
|
||||
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", true]] });
|
||||
|
||||
ok(BrowserTestUtils.isVisible(verticalTabs), "Vertical tabs slot is visible");
|
||||
is(
|
||||
tabStrip.parentNode,
|
||||
verticalTabs,
|
||||
"Tabstrip is slotted into the sidebar vertical tabs container"
|
||||
);
|
||||
|
||||
ok(
|
||||
BrowserTestUtils.isVisible(verticalPinnedTabsContainer),
|
||||
"Vertical pinned tabs container is visible"
|
||||
);
|
||||
is(
|
||||
verticalPinnedTabsContainer.children.length,
|
||||
1,
|
||||
"One tab is pinned in vertical pinned tabs container"
|
||||
);
|
||||
|
||||
is(tabbrowser._numPinnedTabs, 1, "One tab is pinned in global tabstrip");
|
||||
|
||||
tabbrowser.pinTab(tabs[1]);
|
||||
|
||||
is(
|
||||
verticalPinnedTabsContainer.children.length,
|
||||
2,
|
||||
"Two tabs are pinned in the vertical pinned tabs container"
|
||||
);
|
||||
|
||||
is(tabbrowser._numPinnedTabs, 2, "Two tabs are pinned in global tabstrip");
|
||||
indexTest(
|
||||
1,
|
||||
1,
|
||||
"unpinning a tab should move a tab to the start of normal tabs"
|
||||
);
|
||||
|
||||
indexTest(3, 0, "about:home is the first pinned tab");
|
||||
indexTest(1, 1, "about:blank is the second pinned tab");
|
||||
|
||||
await BrowserTestUtils.switchTab(tabbrowser, tabs[1]);
|
||||
is(tabbrowser.selectedTab, tabs[1], "about:blank is the selected tab");
|
||||
|
||||
tabbrowser.moveTabToStart();
|
||||
indexTest(1, 0, "about:blank is now the first pinned tab");
|
||||
indexTest(3, 1, "about:home is now the second pinned tab");
|
||||
is(
|
||||
verticalPinnedTabsContainer.children[0],
|
||||
tabs[1],
|
||||
"about:blank is the first tab in the pinned tabs container"
|
||||
);
|
||||
|
||||
tabbrowser.pinTab(tabs[2]);
|
||||
indexTest(1, 0, "about:blank is now the first pinned tab");
|
||||
indexTest(2, 2, "about:mozilla is now the third pinned tab");
|
||||
indexTest(3, 1, "about:home is now the second pinned tab");
|
||||
|
||||
await BrowserTestUtils.switchTab(tabbrowser, tabs[3]);
|
||||
is(tabbrowser.selectedTab, tabs[3], "about:home is the selected tab");
|
||||
|
||||
tabbrowser.moveTabToEnd();
|
||||
indexTest(1, 0, "about:blank is now the first pinned tab");
|
||||
indexTest(2, 1, "about:mozilla is now the second pinned tab");
|
||||
indexTest(3, 2, "about:home is now the third pinned tab");
|
||||
|
||||
tabbrowser.moveTabTo(tabs[1], 1);
|
||||
indexTest(1, 1, "about:blank is now the second pinned tab");
|
||||
indexTest(2, 0, "about:mozilla is now the first pinned tab");
|
||||
indexTest(3, 2, "about:home is now the third pinned tab");
|
||||
|
||||
is(
|
||||
verticalPinnedTabsContainer.children[2],
|
||||
tabs[3],
|
||||
"about:home is the last tab in the pinned tabs container"
|
||||
);
|
||||
|
||||
// flip the pref to move the tabstrip back into original location
|
||||
await SpecialPowers.pushPrefEnv({ set: [["sidebar.verticalTabs", false]] });
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() => !verticalPinnedTabsContainer.children.length,
|
||||
"Pinned tabs are no longer in vertical pinned tabs container"
|
||||
);
|
||||
is(
|
||||
tabbrowser._numPinnedTabs,
|
||||
3,
|
||||
0,
|
||||
"unpinning a tab should move a tab to the start of normal tabs"
|
||||
"One tab is still pinned in global tabstrip"
|
||||
);
|
||||
indexTest(1, 1, "about:blank is still the second pinned tab");
|
||||
indexTest(2, 0, "about:mozilla is still the first pinned tab");
|
||||
indexTest(3, 2, "about:home is still the third pinned tab");
|
||||
indexTest(0, 3, "initial tab is still the last tab");
|
||||
|
||||
gBrowser.removeTab(tabs[1]);
|
||||
gBrowser.removeTab(tabs[2]);
|
||||
gBrowser.removeTab(tabs[3]);
|
||||
}
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
@ -12,12 +12,13 @@
|
||||
&[uidensity=touch] {
|
||||
--tab-min-height: 41px;
|
||||
}
|
||||
|
||||
--collapsed-tab-width: 40px;
|
||||
--inline-tab-padding: 8px;
|
||||
--tab-border-radius: 4px;
|
||||
--tab-shadow-max-size: 6px;
|
||||
--tab-block-margin: 4px;
|
||||
--tab-loading-fill: #0A84FF;
|
||||
--tab-hover-background-color: color-mix(in srgb, currentColor 11%, transparent);
|
||||
--tab-selected-textcolor: var(--toolbar-color);
|
||||
--tab-selected-bgcolor: var(--toolbar-bgcolor);
|
||||
--tab-selected-color-scheme: var(--toolbar-color-scheme);
|
||||
@ -579,7 +580,7 @@
|
||||
/* Selected tab and tab hover */
|
||||
|
||||
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected], [multiselected]) {
|
||||
background-color: color-mix(in srgb, currentColor 11%, transparent);
|
||||
background-color: var(--tab-hover-background-color);
|
||||
outline-color: var(--tab-hover-outline-color);
|
||||
}
|
||||
|
||||
@ -639,14 +640,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]) > #tabbrowser-arrowscrollbox {
|
||||
/* Add a gap between the last pinned tab and the first visible tab */
|
||||
&:not([orient="vertical"]) > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
|
||||
margin-inline-start: 12px;
|
||||
}
|
||||
&[orient="vertical"] > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
|
||||
margin-block-start: 12px;
|
||||
}
|
||||
#tabbrowser-tabs[haspinnedtabs]:not([positionpinnedtabs]):not([orient="vertical"]) > #tabbrowser-arrowscrollbox > .tabbrowser-tab:nth-child(1 of :not([pinned], [hidden])) {
|
||||
margin-inline-start: 12px;
|
||||
}
|
||||
|
||||
.tab-label[attention]:not([selected]) {
|
||||
@ -746,6 +741,7 @@
|
||||
&::part(scrollbox) {
|
||||
scrollbar-width: thin;
|
||||
overflow-y: auto;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
&[overflowing="true"]:not([scrolledtoend="true"]) {
|
||||
@ -757,26 +753,117 @@
|
||||
border-bottom: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
|
||||
#vertical-tabs {
|
||||
overflow-y: hidden;
|
||||
display: none;
|
||||
#vertical-tabs-newtab-button {
|
||||
display: flex;
|
||||
height: var(--tab-min-height);
|
||||
border-radius: var(--border-radius-medium);
|
||||
padding: 0 var(--space-small);
|
||||
|
||||
&[activated] {
|
||||
display: flex;
|
||||
&:hover {
|
||||
background-color: var(--tab-hover-background-color);
|
||||
}
|
||||
|
||||
> .toolbarbutton-text {
|
||||
text-align: start;
|
||||
padding-inline-start: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
sidebar-main:not([expanded]) > #vertical-tabs > #tabbrowser-tabs[orient="vertical"] .tabbrowser-tab {
|
||||
/* TODO look into handlings this by setting --tab-min-width in tabs.js in bug 1899336. */
|
||||
min-width: inherit;
|
||||
width: inherit;
|
||||
width: var(--collapsed-tab-width);
|
||||
}
|
||||
|
||||
sidebar-main:not([expanded]) > #vertical-tabs > #tabbrowser-tabs[orient="vertical"] .tab-close-button,
|
||||
sidebar-main[expanded] > #vertical-tabs > #tabbrowser-tabs[orient="vertical"] .tab-close-button:not([selected]) {
|
||||
#newtab-button-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#vertical-tabs {
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
|
||||
&[visible] {
|
||||
display: flex;
|
||||
/* make the scrollbars hug the side of the container */
|
||||
margin-inline-end: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
#vertical-pinned-tabs-container {
|
||||
display: none;
|
||||
|
||||
.tab-label-container {
|
||||
display: none;
|
||||
}
|
||||
.tab-background {
|
||||
border-radius: var(--border-radius-medium);
|
||||
|
||||
&:not([selected], [multiselected]) {
|
||||
background-color: color-mix(in srgb, currentColor 7%, transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[orient="vertical"] {
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
align-content: flex-start;
|
||||
grid-gap: var(--space-small);
|
||||
|
||||
.tab-close-button {
|
||||
display: none;
|
||||
}
|
||||
.tab-content {
|
||||
align-content: center;
|
||||
}
|
||||
.tab-background {
|
||||
border-radius: var(--border-radius-medium);
|
||||
}
|
||||
#newtab-button-container {
|
||||
display: flex;
|
||||
border-top: 0;
|
||||
margin-inline-end: var(--space-medium);
|
||||
font-size: var(--urlbarView-small-font-size);
|
||||
flex-direction: column;
|
||||
padding-top: var(--space-small);
|
||||
|
||||
&[showborder] {
|
||||
border-top: 1px solid color-mix(in srgb, currentColor 25%, transparent);
|
||||
}
|
||||
|
||||
sidebar-main:not([expanded]) & {
|
||||
.toolbarbutton-text {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
#vertical-pinned-tabs-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(var(--collapsed-tab-width), auto));
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
scrollbar-width: thin;
|
||||
/* Fit slightly more than 5 tabs + padding before overflowing */
|
||||
max-height: 244px;
|
||||
column-gap: 4px;
|
||||
padding-inline-end: var(--space-medium);
|
||||
}
|
||||
}
|
||||
|
||||
sidebar-main[expanded] #tabbrowser-tabs[orient="vertical"] #newtab-button-container {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
sidebar-main:not([expanded]) {
|
||||
.tab-label-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
sidebar-main[expanded] > #vertical-tabs > #tabbrowser-tabs[orient="vertical"] > #tabbrowser-arrowscrollbox > .tabbrowser-tab:is(:hover, [selected]) .tab-close-button {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Tab drag and drop */
|
||||
|
||||
.tab-drop-indicator {
|
||||
@ -844,11 +931,13 @@ toolbar:not(#TabsToolbar) #firefox-view-button {
|
||||
/* New tab button */
|
||||
|
||||
#tabs-newtab-button,
|
||||
#vertical-tabs-newtab-button,
|
||||
#TabsToolbar #new-tab-button {
|
||||
list-style-image: url(chrome://global/skin/icons/plus.svg);
|
||||
}
|
||||
|
||||
#tabbrowser-tabs[hasadjacentnewtabbutton]:not([overflow]) ~ #new-tab-button,
|
||||
#tabbrowser-tabs[orient="vertical"] > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
|
||||
#tabbrowser-tabs[overflow] > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
|
||||
#tabbrowser-tabs:not([hasadjacentnewtabbutton]) > #tabbrowser-arrowscrollbox > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button,
|
||||
#TabsToolbar[customizing] #tabs-newtab-button {
|
||||
|
Loading…
Reference in New Issue
Block a user