diff --git a/chrome/content/zotero/contextPane.js b/chrome/content/zotero/contextPane.js
index 2cc4876b38..41c5254820 100644
--- a/chrome/content/zotero/contextPane.js
+++ b/chrome/content/zotero/contextPane.js
@@ -57,12 +57,10 @@ var ZoteroContextPane = new function () {
_contextPaneInner.setAttribute('collapsed', !!collapsed);
_contextPaneSplitter.setAttribute('state', collapsed ? 'collapsed' : 'open');
_contextPaneSplitterStacked.setAttribute('state', collapsed ? 'collapsed' : 'open');
- _update();
+ this.update();
}
});
- this.update = _update;
-
this.focus = () => {
return _contextPaneInner.handleFocus();
};
@@ -71,10 +69,6 @@ var ZoteroContextPane = new function () {
_loadingMessageContainer.classList.toggle('hidden', !isShow);
};
- this.updateAddToNote = _updateAddToNote;
-
- this.togglePane = _togglePane;
-
this.init = function () {
if (!Zotero) {
return;
@@ -93,18 +87,18 @@ var ZoteroContextPane = new function () {
this.context = _contextPaneInner;
- window.addEventListener('resize', _update);
- Zotero.Reader.onChangeSidebarWidth = _updatePaneWidth;
- Zotero.Reader.onToggleSidebar = _updatePaneWidth;
+ window.addEventListener('resize', this.update);
+ Zotero.Reader.onChangeSidebarWidth = this._updatePaneWidth;
+ Zotero.Reader.onToggleSidebar = this._updatePaneWidth;
};
this.destroy = function () {
- window.removeEventListener('resize', _update);
+ window.removeEventListener('resize', this.update);
Zotero.Reader.onChangeSidebarWidth = () => {};
Zotero.Reader.onToggleSidebar = () => {};
};
- function _updateAddToNote() {
+ this.updateAddToNote = () => {
let reader = Zotero.Reader.getByTabID(Zotero_Tabs.selectedID);
if (reader) {
let editor = ZoteroContextPane.activeEditor;
@@ -113,34 +107,28 @@ var ZoteroContextPane = new function () {
&& (editor.item.deleted || editor.item.parentItem && editor.item.parentItem.deleted);
reader.enableAddToNote(!!editor && !libraryReadOnly && !noteReadOnly);
}
- }
+ };
- function _updatePaneWidth() {
+ this._updatePaneWidth = () => {
let stacked = _isStacked();
- let width = Zotero.Reader.getSidebarWidth() + 'px';
- if (!Zotero.Reader.getSidebarOpen()) {
- width = 0;
- }
+ let readerSidebarWidth = (Zotero.Reader.getSidebarOpen() ? Zotero.Reader.getSidebarWidth() : 0)
+ + 'px';
let contextPaneWidth = _contextPane.getAttribute("width");
if (contextPaneWidth && !_contextPane.style.width) {
_contextPane.style.width = `${contextPaneWidth}px`;
}
if (Zotero.rtl) {
_contextPane.style.left = 0;
- _contextPane.style.right = stacked ? width : 'unset';
+ _contextPane.style.right = stacked ? readerSidebarWidth : 'unset';
}
else {
- _contextPane.style.left = stacked ? width : 'unset';
+ _contextPane.style.left = stacked ? readerSidebarWidth : 'unset';
_contextPane.style.right = 0;
}
- }
+ };
- function _isStacked() {
- return Zotero.Prefs.get('layout') == 'stacked';
- }
-
- function _update() {
- if (Zotero_Tabs.selectedIndex == 0) {
+ this.update = () => {
+ if (Zotero_Tabs.selectedType === 'library') {
return;
}
if (_isStacked()) {
@@ -174,28 +162,32 @@ var ZoteroContextPane = new function () {
_contextPane.style.width = `${_contextPane.getAttribute("width")}px`;
}
- if (Zotero_Tabs.selectedIndex > 0) {
- var height = null;
- if (_isStacked()) {
- height = 0;
- if (_contextPane.getAttribute('collapsed') != 'true') {
- height = _contextPaneInner.getBoundingClientRect().height;
- }
- }
- Zotero.Reader.setBottomPlaceholderHeight(height);
- }
+ Zotero.Reader.setContextPaneOpen(!this.collapsed);
- _updatePaneWidth();
- _updateAddToNote();
+ var height = null;
+ if (_isStacked()) {
+ height = 0;
+ if (_contextPane.getAttribute('collapsed') != 'true') {
+ height = _contextPaneInner.getBoundingClientRect().height;
+ }
+ }
+ Zotero.Reader.setBottomPlaceholderHeight(height);
+
+ this._updatePaneWidth();
+ this.updateAddToNote();
ZoteroPane.updateLayoutConstraints();
+ };
+
+ this.togglePane = () => {
+ this.collapsed = !this.collapsed;
+ };
+
+ function _isStacked() {
+ return Zotero.Prefs.get('layout') == 'stacked';
}
-
+
function _isLibraryReadOnly(libraryID) {
return !Zotero.Libraries.get(libraryID).editable;
}
-
- function _togglePane() {
- this.collapsed = !this.collapsed;
- }
};
diff --git a/chrome/content/zotero/elements/itemPaneSidenav.js b/chrome/content/zotero/elements/itemPaneSidenav.js
index 6b4195a7e1..b0146082b7 100644
--- a/chrome/content/zotero/elements/itemPaneSidenav.js
+++ b/chrome/content/zotero/elements/itemPaneSidenav.js
@@ -28,6 +28,14 @@
{
class ItemPaneSidenav extends XULElementBase {
content = MozXULElement.parseXULToFragment(`
+
+
+
+
+
@@ -215,6 +223,11 @@
for (let button of this.querySelectorAll('.btn[data-action]')) {
let action = button.dataset.action;
+ if (action === 'toggle-pane') {
+ button.addEventListener('command', () => {
+ this._collapsed = !this._collapsed;
+ });
+ }
if (action === 'locate') {
button.addEventListener('mousedown', async (event) => {
if (event.button !== 0 || button.open) {
@@ -313,9 +326,15 @@
for (let button of this.querySelectorAll('.btn[data-action]')) {
let action = button.dataset.action;
- if (action == 'locate') {
+ if (action == 'toggle-pane' || action == 'locate') {
button.parentElement.hidden = false;
}
+ if (action == 'toggle-pane') {
+ document.l10n.setAttributes(button,
+ Zotero_Tabs.selectedType === 'library'
+ ? 'toggle-item-pane'
+ : 'toggle-context-pane');
+ }
}
this.querySelector('.highlight-notes-active').classList.toggle('highlight', contextNotesPaneVisible);
@@ -601,7 +620,7 @@
return {
index,
position: index === 0 ? 0 : index * (btnSize + btnGap) + btnGap / 2
- }
+ };
};
handleKeyDown = (event) => {
diff --git a/chrome/content/zotero/xpcom/reader.js b/chrome/content/zotero/xpcom/reader.js
index eb1fbd3d4f..14a849aad4 100644
--- a/chrome/content/zotero/xpcom/reader.js
+++ b/chrome/content/zotero/xpcom/reader.js
@@ -201,6 +201,7 @@ class ReaderInstance {
sidebarWidth: this._sidebarWidth,
sidebarOpen: this._sidebarOpen,
bottomPlaceholderHeight: this._bottomPlaceholderHeight,
+ contextPaneOpen: this._contextPaneOpen,
rtl: Zotero.rtl,
fontSize: Zotero.Prefs.get('fontSize'),
localizedStrings: {
@@ -1236,6 +1237,7 @@ class ReaderTab extends ReaderInstance {
super(options);
this._sidebarWidth = options.sidebarWidth;
this._sidebarOpen = options.sidebarOpen;
+ this._contextPaneOpen = options.bottomPlaceholderHeight;
this._bottomPlaceholderHeight = options.bottomPlaceholderHeight;
this._showContextPaneToggle = true;
this._onToggleSidebarCallback = options.onToggleSidebar;
@@ -1388,6 +1390,7 @@ class ReaderWindow extends ReaderInstance {
super(options);
this._sidebarWidth = options.sidebarWidth;
this._sidebarOpen = options.sidebarOpen;
+ this._contextPaneOpen = false;
this._bottomPlaceholderHeight = 0;
this._onClose = options.onClose;
@@ -1800,6 +1803,7 @@ class Reader {
constructor() {
this._sidebarWidth = 240;
this._sidebarOpen = false;
+ this._contextPaneOpen = false;
this._bottomPlaceholderHeight = 0;
this._readers = [];
this._notifierID = Zotero.Notifier.registerObserver(this, ['item', 'setting', 'tab'], 'reader');
@@ -1925,6 +1929,14 @@ class Reader {
}
this._setSidebarState();
}
+
+ setContextPaneOpen(open) {
+ this._contextPaneOpen = open;
+ let readers = this._readers.filter(r => r instanceof ReaderTab);
+ for (let reader of readers) {
+ reader.setContextPaneOpen(open);
+ }
+ }
setBottomPlaceholderHeight(height) {
this._bottomPlaceholderHeight = height;
@@ -2107,6 +2119,7 @@ class Reader {
background: openInBackground,
sidebarWidth: this._sidebarWidth,
sidebarOpen: this._sidebarOpen,
+ contextPaneOpen: this._contextPaneOpen,
bottomPlaceholderHeight: this._bottomPlaceholderHeight,
preventJumpback: preventJumpback,
onToggleSidebar: (open) => {
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index cdba26f7eb..ebf7afc17b 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -6853,8 +6853,14 @@ var ZoteroPane = new function()
this.handleTagSelectorResize();
this.itemPane.handleResize();
- }
-
+ };
+
+
+ this.toggleItemPane = function () {
+ this.itemPane.collapsed = !this.itemPane.collapsed;
+ this.updateLayoutConstraints();
+ };
+
// Set the label of the dynamic tooltip. Can be used when we cannot set .tooltiptext
// property, e.g. if we don't want the tooltip to be announced by screenreaders.
diff --git a/chrome/content/zotero/zoteroPane.xhtml b/chrome/content/zotero/zoteroPane.xhtml
index 595f90399f..2dfc4e7c77 100644
--- a/chrome/content/zotero/zoteroPane.xhtml
+++ b/chrome/content/zotero/zoteroPane.xhtml
@@ -1344,6 +1344,15 @@
onkeydown="ZoteroPane_Local.handleSearchKeypress(this, event)"
oninput="ZoteroPane_Local.handleSearchInput(this, event)"
oncommand="ZoteroPane_Local.search()"/>
+
+
+
diff --git a/chrome/locale/en-US/zotero/zotero.ftl b/chrome/locale/en-US/zotero/zotero.ftl
index 51fee32b99..ceffca5850 100644
--- a/chrome/locale/en-US/zotero/zotero.ftl
+++ b/chrome/locale/en-US/zotero/zotero.ftl
@@ -537,6 +537,11 @@ sidenav-reorder-down =
sidenav-reorder-reset =
.label = Reset Section Order
+toggle-item-pane =
+ .tooltiptext = Toggle Item Pane
+toggle-context-pane =
+ .tooltiptext = Toggle Context Pane
+
pin-section =
.label = Pin Section
unpin-section =
diff --git a/chrome/skin/default/zotero/20/universal/sidebar-bottom.svg b/chrome/skin/default/zotero/20/universal/sidebar-bottom.svg
new file mode 100644
index 0000000000..c17e5f48df
--- /dev/null
+++ b/chrome/skin/default/zotero/20/universal/sidebar-bottom.svg
@@ -0,0 +1,5 @@
+
diff --git a/chrome/skin/default/zotero/20/universal/sidebar.svg b/chrome/skin/default/zotero/20/universal/sidebar.svg
new file mode 100644
index 0000000000..6ae4c33f0e
--- /dev/null
+++ b/chrome/skin/default/zotero/20/universal/sidebar.svg
@@ -0,0 +1,6 @@
+
diff --git a/scss/components/_toolbar.scss b/scss/components/_toolbar.scss
index a6615561f8..7265502e4e 100644
--- a/scss/components/_toolbar.scss
+++ b/scss/components/_toolbar.scss
@@ -122,6 +122,20 @@
margin-top: 1px;
}
+#zotero-tb-toggle-item-pane-stacked {
+ // Hidden except in Stacked mode
+ display: none;
+}
+
+#main-window.stacked #zotero-toolbar-item-tree {
+ padding-inline-end: 0;
+
+ #zotero-tb-toggle-item-pane-stacked { // Keep nested for specificity
+ display: flex;
+ margin-inline-start: 9px;
+ }
+}
+
toolbox {
@media (-moz-platform: linux) {
background: Menu;
diff --git a/scss/components/_toolbarbutton.scss b/scss/components/_toolbarbutton.scss
index 5ea8e80731..13a136a2ba 100644
--- a/scss/components/_toolbarbutton.scss
+++ b/scss/components/_toolbarbutton.scss
@@ -74,6 +74,7 @@ $toolbarbutton-icons: (
tabs-menu: "chevron",
sync-error: "error",
sync: "sync",
+ toggle-item-pane-stacked: "sidebar-bottom",
);
@each $cls, $icon in $toolbarbutton-icons {
diff --git a/scss/elements/_itemPaneSidenav.scss b/scss/elements/_itemPaneSidenav.scss
index c1a23a5c5e..c06e1f069f 100644
--- a/scss/elements/_itemPaneSidenav.scss
+++ b/scss/elements/_itemPaneSidenav.scss
@@ -108,16 +108,35 @@ item-pane-sidenav {
stroke: map.get($item-pane-sections, "notes");
}
- // Locate button
- &[data-action="locate"] {
+ &[data-action="locate"], &[data-action="toggle-pane"] {
color: var(--fill-secondary);
+ }
+
+ &[data-action="locate"] {
@include svgicon-menu("go-to", "universal", "20");
-
+
+ // Locate is flipped in RTL
&:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
}
+ &[data-action="toggle-pane"] {
+ @include svgicon-menu("sidebar", "universal", "20");
+
+ // ...And Toggle Item/Context Pane is flipped in LTR
+ &:-moz-locale-dir(ltr) {
+ transform: scaleX(-1);
+ }
+
+ // Hide in Stacked mode, since we show it in the toolbar instead
+ @include state("item-pane-sidenav.stacked") {
+ &, & + .divider {
+ display: none;
+ }
+ }
+ }
+
&[custom] {
@media (prefers-color-scheme: light) {
background-image: var(--custom-sidenav-icon-light);