From 744aba091a56159240c60ba935e652aec4e29e48 Mon Sep 17 00:00:00 2001 From: Abe Jellinek <1770299+AbeJellinek@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:41:10 -0600 Subject: [PATCH] Reader: Add support code for popup position persistence (cherry picked from commit ad7159834c9f63fe3e562fbb3245dfc0de2de5c3) --- chrome/content/zotero/xpcom/reader.js | 31 +++++++++++++++++++++++++++ defaults/preferences/zotero.js | 1 + 2 files changed, 32 insertions(+) diff --git a/chrome/content/zotero/xpcom/reader.js b/chrome/content/zotero/xpcom/reader.js index 025af05de3..89e4bc7e6c 100644 --- a/chrome/content/zotero/xpcom/reader.js +++ b/chrome/content/zotero/xpcom/reader.js @@ -260,6 +260,7 @@ class ReaderInstance { autoDisableTextTool: Zotero.Prefs.get('reader.autoDisableTool.text'), autoDisableImageTool: Zotero.Prefs.get('reader.autoDisableTool.image'), sidebarView: Zotero.Prefs.get('reader.lastSidebarTab'), + popupPositions: this._getPopupPositions(), enableReadAloud: true, readAloudVoices: this._getReadAloudVoices(), readAloudEnabledVoices: await this._getReadAloudEnabledVoices(), @@ -403,6 +404,9 @@ class ReaderInstance { onChangeSidebarView: (view) => { Zotero.Prefs.set('reader.lastSidebarTab', view); }, + onSetPopupPosition: (id, position) => { + this._setPopupPosition(id, position); + }, onFocusContextPane: () => { if (this instanceof ReaderWindow || !this._window.ZoteroContextPane.focus()) { this.focusFirst(); @@ -662,6 +666,7 @@ class ReaderInstance { Zotero.Prefs.registerObserver('reader.autoDisableTool.note', this._handleAutoDisableToolPrefChange), Zotero.Prefs.registerObserver('reader.autoDisableTool.text', this._handleAutoDisableToolPrefChange), Zotero.Prefs.registerObserver('reader.autoDisableTool.image', this._handleAutoDisableToolPrefChange), + Zotero.Prefs.registerObserver('reader.popupPositions', this._handlePopupPositionsPrefChange), Zotero.Prefs.registerObserver('reader.readAloudVoices', this._handleReadAloudVoicesPrefChange), Zotero.Prefs.registerObserver('reader.readAloud.highlightGranularity', this._handleReadAloudHighlightGranularityChange), ]; @@ -1221,6 +1226,10 @@ class ReaderInstance { this._internalReader.setAutoDisableImageTool(Zotero.Prefs.get('reader.autoDisableTool.image')); }; + _handlePopupPositionsPrefChange = () => { + this._internalReader.setPopupPositions(Cu.cloneInto(this._getPopupPositions(), this._iframeWindow)); + }; + _handleReadAloudVoicesPrefChange = () => { this._internalReader.setReadAloudVoices(Cu.cloneInto(this._getReadAloudVoices(), this._iframeWindow)); }; @@ -1683,6 +1692,28 @@ class ReaderInstance { } } + /** + * Positions of draggable reader popups, keyed by popup ID + * + * @returns {Object} + */ + _getPopupPositions() { + try { + let positions = JSON.parse(Zotero.Prefs.get('reader.popupPositions')); + return positions && typeof positions == 'object' ? positions : {}; + } + catch { + return {}; + } + } + + _setPopupPosition(id, position) { + Zotero.Prefs.set('reader.popupPositions', JSON.stringify({ + ...this._getPopupPositions(), + [id]: { x: Math.round(position.x), y: Math.round(position.y) }, + })); + } + _getReadAloudVoices() { try { return JSON.parse(Zotero.Prefs.get('reader.readAloudVoices')); diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index 02d8aaa8ce..573b38c9ad 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -249,6 +249,7 @@ pref("extensions.zotero.reader.autoDisableTool.note", true); pref("extensions.zotero.reader.autoDisableTool.text", true); pref("extensions.zotero.reader.autoDisableTool.image", true); pref("extensions.zotero.reader.lastSidebarTab", "annotations"); +pref("extensions.zotero.reader.popupPositions", "{}"); pref("extensions.zotero.reader.readAloud.highlightGranularity", "sentence"); // Set color scheme to auto by default