From adaa61f2cfcaced1ded9c22438e6484ec62bf4dc Mon Sep 17 00:00:00 2001 From: abaevbog Date: Wed, 1 May 2024 02:00:15 -0400 Subject: [PATCH] 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 --- chrome/content/zotero/tabs.js | 50 ++++++++++++++++++++++++++ chrome/content/zotero/zoteroPane.xhtml | 2 +- scss/components/_tabsMenu.scss | 13 +++++-- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/chrome/content/zotero/tabs.js b/chrome/content/zotero/tabs.js index 2a5df3c917..104610f333 100644 --- a/chrome/content/zotero/tabs.js +++ b/chrome/content/zotero/tabs.js @@ -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 */ diff --git a/chrome/content/zotero/zoteroPane.xhtml b/chrome/content/zotero/zoteroPane.xhtml index 69db59a741..4525b97696 100644 --- a/chrome/content/zotero/zoteroPane.xhtml +++ b/chrome/content/zotero/zoteroPane.xhtml @@ -840,7 +840,7 @@