diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js index 6eea8c82a8..2cc4876b38 100644 --- a/chrome/content/zotero/contextPane.js +++ b/chrome/content/zotero/contextPane.js @@ -48,6 +48,19 @@ var ZoteroContextPane = new function () { : _contextPaneSplitter) }); + Object.defineProperty(this, 'collapsed', { + get: () => { + return this.splitter.getAttribute('state') === 'collapsed'; + }, + set: (collapsed) => { + _contextPane.setAttribute('collapsed', !!collapsed); + _contextPaneInner.setAttribute('collapsed', !!collapsed); + _contextPaneSplitter.setAttribute('state', collapsed ? 'collapsed' : 'open'); + _contextPaneSplitterStacked.setAttribute('state', collapsed ? 'collapsed' : 'open'); + _update(); + } + }); + this.update = _update; this.focus = () => { @@ -132,7 +145,6 @@ var ZoteroContextPane = new function () { } if (_isStacked()) { _contextPaneSplitterStacked.setAttribute('hidden', false); - _contextPaneSplitter.setAttribute('state', 'open'); _contextPaneSplitter.setAttribute('hidden', true); _contextPane.classList.add('stacked'); _contextPane.classList.remove('standard'); @@ -149,7 +161,6 @@ var ZoteroContextPane = new function () { else { _contextPaneSplitter.setAttribute('hidden', false); _contextPaneSplitterStacked.setAttribute('hidden', true); - _contextPaneSplitterStacked.setAttribute('state', 'open'); _contextPane.classList.add('standard'); _contextPane.classList.remove('stacked'); _readerSidenav.classList.remove('stacked'); @@ -176,6 +187,8 @@ var ZoteroContextPane = new function () { _updatePaneWidth(); _updateAddToNote(); + + ZoteroPane.updateLayoutConstraints(); } function _isLibraryReadOnly(libraryID) { @@ -183,15 +196,6 @@ var ZoteroContextPane = new function () { } function _togglePane() { - var splitter = ZoteroContextPane.splitter; - - var open = true; - if (splitter.getAttribute('state') != 'collapsed') { - open = false; - } - - _contextPane.setAttribute('collapsed', !open); - splitter.setAttribute('state', open ? 'open' : 'collapsed'); - _update(); + this.collapsed = !this.collapsed; } }; diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 17c59252d6..7c09abd955 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -6248,8 +6248,7 @@ var ZoteroPane = new function() */ this.unserializePersist = function () { _unserialized = true; - var serializedValues = Zotero.Prefs.get("pane.persist"); - if (!serializedValues) return; + var serializedValues = Zotero.Prefs.get("pane.persist") || "{}"; serializedValues = JSON.parse(serializedValues); for (var id in serializedValues) { @@ -6354,33 +6353,73 @@ var ZoteroPane = new function() var itemsPaneContainer = document.getElementById('zotero-items-pane-container'); var collectionsPane = document.getElementById("zotero-collections-pane"); var tagSelector = document.getElementById("zotero-tag-selector"); - + let layoutModeMenus = [ + document.getElementById("view-menuitem-standard"), + document.getElementById("view-menuitem-stacked"), + ]; + + let isStackedMode = Zotero.Prefs.get('layout') === 'stacked'; + let isTempStackedMode = Zotero.Prefs.get('tempStackedMode'); + let isItemPaneCollapsed = ZoteroPane.itemPane.collapsed && ZoteroContextPane.collapsed; + + // Keep in sycn with abstracts/variables.scss > $min-width-collections-pane + const collectionsPaneMinWidth = collectionsPane.hasAttribute("collapsed") ? 0 : 200; + // Keep in sycn with abstracts/variables.scss > $min-width-item-pane + const itemPaneMinWidth = (isStackedMode || isItemPaneCollapsed) ? 0 : 320; + const libraryItemPaneMinWidth = (isStackedMode || ZoteroPane.itemPane.collapsed) ? 0 : 320; + // Keep in sycn with abstracts/variables.scss > $width-sidenav + const sideNavMinWidth = isStackedMode ? 0 : 37; + // Keep in sycn with abstracts/variables.scss > $min-width-items-pane + const itemsPaneMinWidth = 370; + + let fixedComponentWidth = collectionsPaneMinWidth + itemPaneMinWidth + sideNavMinWidth; + // Calculate the heights of the components that aren't able to shrink automatically // when the window is resized - let fixedComponentWidth = trees.scrollWidth - itemsPaneContainer.scrollWidth; let fixedComponentHeight = titlebar.scrollHeight + trees.scrollHeight - itemsPaneContainer.scrollHeight; document.documentElement.style.setProperty('--width-of-fixed-components', `${fixedComponentWidth}px`); document.documentElement.style.setProperty('--height-of-fixed-components', `${fixedComponentHeight}px`); + let layoutChanged = false; + // Collections pane + items pane + items pane + sidenav + 3px for draggability + const windowAutoStackMinWidth = 930; + if (window.innerWidth < windowAutoStackMinWidth) { + // Disable layout mode menus because the standard mode is not available + layoutModeMenus.forEach(menu => menu.setAttribute("disabled", "true")); + // If the window is too small in standard mode, enter stack mode temporarily + if (!isStackedMode && !isTempStackedMode) { + Zotero.Prefs.set('tempStackedMode', true); + Zotero.Prefs.set('layout', 'stacked'); + layoutChanged = true; + } + } + else { + layoutModeMenus.forEach(menu => menu.removeAttribute("disabled")); + if (isTempStackedMode) { + Zotero.Prefs.clear('tempStackedMode'); + Zotero.Prefs.set('layout', 'standard'); + layoutChanged = true; + } + } + + if (layoutChanged) { + // Compute the layout constraints again after the layout change to avoid weirdness + setTimeout(() => { + this.updateLayoutConstraints(); + }, 0); + } + + // This is important to avoid other panes be pushed out of the window + collectionsPane.style.setProperty( + "--max-width-collections-pane", + `${window.innerWidth - libraryItemPaneMinWidth - sideNavMinWidth - itemsPaneMinWidth}px`); + var collectionsPaneWidth = collectionsPane.getBoundingClientRect().width; tagSelector.style.maxWidth = collectionsPaneWidth + 'px'; if (ZoteroPane.itemsView) { ZoteroPane.itemsView.updateHeight(); } - // Temp JS solution to shrink the collection search so that it does not overflow outside - // of the collection pane - var collectionSearch = document.getElementById("zotero-collections-search"); - collectionSearch.removeAttribute("data-expanded-width"); - if (collectionsPaneWidth < 220) { - collectionSearch.setAttribute("data-expanded-width", 150); - if (collectionSearch.classList.contains("visible")) { - collectionSearch.style.maxWidth = "150px"; - } - } - else { - collectionSearch.style.removeProperty('max-width'); - } - + this.handleTagSelectorResize(); this.itemPane.handleResize(); diff --git a/chrome/content/zotero/zoteroPane.xhtml b/chrome/content/zotero/zoteroPane.xhtml index 9160421da1..7e20b6354c 100644 --- a/chrome/content/zotero/zoteroPane.xhtml +++ b/chrome/content/zotero/zoteroPane.xhtml @@ -1075,7 +1075,7 @@ - + - + - + @@ -1344,7 +1344,7 @@ - + :not(.deck-selected) { // Hide all sub-trees that are in the invisible tab deck @@ -11,6 +13,8 @@ #zotero-context-pane { display: flex; + flex-grow: 0; + flex-shrink: 1; min-width: $min-width-context-pane + $width-sidenav; .divider { diff --git a/scss/components/_item-tree.scss b/scss/components/_item-tree.scss index c2f3966d87..43331ef71d 100644 --- a/scss/components/_item-tree.scss +++ b/scss/components/_item-tree.scss @@ -1,6 +1,8 @@ @use "sass:map"; #zotero-items-pane-container { + flex-grow: 1; + flex-shrink: 1; min-width: $min-width-items-pane; height: 150px; min-height: $min-height-items-pane; diff --git a/scss/components/_mainWindow.scss b/scss/components/_mainWindow.scss index 3795897a42..d796a297a7 100644 --- a/scss/components/_mainWindow.scss +++ b/scss/components/_mainWindow.scss @@ -38,4 +38,30 @@ #zotero-pane-progressmeter-container { padding: 10px; -} \ No newline at end of file +} + +#zotero-layout-switcher { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + + /* + Fx115: make panes occupy all available width/height after layout switch + or splitter expand/collapse. + The splitter element stores state in the style attribute's width/height + properties, and if we remove them, the splitter breaks. So we override + them here with !important. + */ + &[orient="horizontal"] :is(#zotero-items-pane-container, #zotero-item-pane) { + height: auto !important; + } + + &[orient="vertical"], + &[orient="vertical"] :is(#zotero-items-pane-container, #zotero-item-pane) { + width: auto !important; + /* min-width: 0 is required here to allow the pane to shrink in Stacked view, + but the child #zotero-items-pane sets a larger min-width, and the splitter + follows that instead of this. */ + min-width: 0 !important; + } +} diff --git a/scss/components/_toolbar.scss b/scss/components/_toolbar.scss index cc35b2da72..a6615561f8 100644 --- a/scss/components/_toolbar.scss +++ b/scss/components/_toolbar.scss @@ -88,6 +88,12 @@ visibility: hidden; } +#zotero-collections-toolbar { + flex-grow: 1; + flex-shrink: 1; + min-width: 0; +} + .zotero-tb-button { -moz-user-focus: normal; } diff --git a/scss/elements/_itemPane.scss b/scss/elements/_itemPane.scss index 755d5a5e5d..ae92ed95be 100644 --- a/scss/elements/_itemPane.scss +++ b/scss/elements/_itemPane.scss @@ -1,5 +1,7 @@ item-pane { - min-width: $min-width-item-pane + $width-sidenav; + flex-grow: 0; + flex-shrink: 1; + min-width: var(--width-available-item-pane, $min-width-item-pane + $width-sidenav); min-height: $min-width-item-pane + $width-sidenav; &[collapsed="true"] {