Make opened tabs menu scrollable (#3833)

- If there are too many tabs opened to fit onto the screen,
the tabs menu can be scrolled
- When tabs menu is opened, scroll to the selected tab
- Use margins instead of padding to that the scrollbar does not
overlap with the cross button
- Make sure that if the tabs menu is long, there will
be a gap between it's top/bottom and the edge of the
screen
- On linux, screen.availTop and screen.availHeight are not always
correct and the menu can go outside of what is supposed to be
the available screen area. Special treatment for those
edge cases
This commit is contained in:
abaevbog 2024-05-01 02:00:15 -04:00 committed by GitHub
parent 9f453b55ad
commit adaa61f2cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 61 additions and 4 deletions

View file

@ -979,12 +979,62 @@ var Zotero_Tabs = new function () {
let menuFilter = document.getElementById('zotero-tabs-menu-filter');
menuFilter.value = "";
this._tabsMenuFilter = "";
this.tabsMenuList.closest("panel").style.removeProperty('max-height');
};
this.handleTabsMenuShown = function (_) {
focusTabsMenuEntry(0);
};
this.handleTabsMenuShowing = function (_) {
this.refreshTabsMenuList();
// Make sure that if the menu is very long, there is a small
// gap left between the top/bottom of the menu and the edge of the screen
let valuesAreWithinMargin = (valueOne, valueTwo, margin) => {
return Math.abs(valueOne - valueTwo) <= margin;
};
let panel = document.getElementById("zotero-tabs-menu-panel");
let panelRect = panel.getBoundingClientRect();
const gapBeforeScreenEdge = 25;
let absoluteTabsMenuTop = window.screenY - panelRect.height + panelRect.bottom;
let absoluteTabsMenuBottom = window.screenY + panelRect.height + panelRect.top;
// On windows, getBoundingClientRect does not give us correct top and bottom values
// until popupshown, so instead use the anchor's position
if (Zotero.isWin) {
let anchor = document.getElementById("zotero-tb-tabs-menu");
let anchorRect = anchor.getBoundingClientRect();
absoluteTabsMenuTop = window.screenY - panelRect.height + anchorRect.top;
absoluteTabsMenuBottom = window.screenY + panelRect.height + anchorRect.bottom;
}
// screen.availTop is not always right on Linux, so ignore it
let availableTop = Zotero.isLinux ? 0 : screen.availTop;
// Check if the end of the tabs menu is close to the edge of the screen
let atTopScreenEdge = valuesAreWithinMargin(absoluteTabsMenuTop, availableTop, gapBeforeScreenEdge);
let atBottomScreenEdge = valuesAreWithinMargin(absoluteTabsMenuBottom, screen.availHeight + availableTop, gapBeforeScreenEdge);
let gap;
// Limit max height of the menu to leave the specified gap till the screen's edge.
// Due to screen.availTop behavior on linux, the menu can go outside of what is supposed
// to be the available screen area, so special treatment for those edge cases.
if (atTopScreenEdge || (Zotero.isLinux && absoluteTabsMenuTop < 0)) {
gap = gapBeforeScreenEdge - (absoluteTabsMenuTop - availableTop);
}
if (atBottomScreenEdge || (Zotero.isLinux && absoluteTabsMenuBottom > screen.availHeight)) {
gap = gapBeforeScreenEdge - (screen.availHeight + availableTop - absoluteTabsMenuBottom);
}
if (gap) {
panel.style.maxHeight = `${panelRect.height - gap}px`;
}
// Try to scroll selected tab into the center
let selectedTab = this.tabsMenuList.querySelector(".selected");
if (selectedTab) {
selectedTab.scrollIntoView({ block: 'center' });
}
};
/**
* Record the value of the filter
*/

View file

@ -840,7 +840,7 @@
<div xmlns="http://www.w3.org/1999/xhtml" class="zotero-tb-separator"></div>
<panel id="zotero-tabs-menu-panel" type="arrow"
onpopuphiding="Zotero_Tabs.handleTabsMenuHiding(event)"
onpopupshowing="Zotero_Tabs.refreshTabsMenuList()"
onpopupshowing="Zotero_Tabs.handleTabsMenuShowing(event)"
onpopupshown="Zotero_Tabs.handleTabsMenuShown(event)"
onkeydown="Zotero_Tabs.handleTabsMenuKeyPress(event)"
tabindex="-1"

View file

@ -6,13 +6,16 @@
#zotero-tabs-menu-wrapper {
width: 350px;
background: var(--material-sidepane);
padding: 7px;
padding: 0;
border-radius: 5px;
--width-focus-border: 2px;
display: flex;
flex-direction: column;
min-height: 0;
}
#zotero-tabs-menu-filter {
margin: 0 0 7px 0;
margin: 7px 7px 2px 7px;
border-radius: 5px;
border: 1px solid transparent;
padding-inline-start: 5px !important;
@ -26,10 +29,14 @@
#zotero-tabs-menu-list {
appearance: none;
margin: 0;
overflow-x: hidden;
overflow-y: scroll;
scrollbar-width: thin;
padding: 5px 0;
.row {
display: flex;
padding-inline-start: 4px;
padding-inline: 4px;
}
.zotero-tabs-menu-entry {