From 31e2e9545213860c52af56be34570d997fdc972e Mon Sep 17 00:00:00 2001 From: abaevbog Date: Tue, 26 Aug 2025 22:43:02 -0500 Subject: [PATCH] itembox: restore unsaved input value after refresh (#5517) If itemBox refresh happens when an input is focused and has some unsaved changes, restore the value of the input after the refresh. Potential solution for: https://forums.zotero.org/discussion/126273/bug-data-that-is-input-is-not-saved-and-needs-to-be-entered-again --- chrome/content/zotero/elements/itemBox.js | 11 ++++++++++- test/tests/itemPaneTest.js | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/chrome/content/zotero/elements/itemBox.js b/chrome/content/zotero/elements/itemBox.js index c3b926bda0..f22581f129 100644 --- a/chrome/content/zotero/elements/itemBox.js +++ b/chrome/content/zotero/elements/itemBox.js @@ -60,6 +60,7 @@ this._initialVisibleCreators = 5; this._draggedCreator = false; this._selectField = null; + this._selectFieldValue = null; this._selectFieldSelection = null; this._addCreatorRow = false; this._switchedModeOfCreator = null; @@ -2522,7 +2523,7 @@ // Save the field ID this._selectField = fieldID; - // Save selection inside inputs + // Save selection and value inside inputs let targetInput = activeElement.closest("input, textarea"); if (targetInput) { this._selectFieldSelection = [ @@ -2530,12 +2531,15 @@ targetInput.selectionEnd, targetInput.selectionDirection, ]; + // Save the value in case it was changed but not saved + this._selectFieldValue = targetInput.value; } } _clearSavedFieldFocus() { this._selectField = null; this._selectFieldSelection = null; + this._selectFieldValue = null; } _restoreFieldFocus() { @@ -2565,6 +2569,11 @@ if (this._selectFieldSelection) { let input = refocusField.querySelector("input, textarea"); if (input) { + // Restore the potentially unsaved value + if (this._selectFieldValue) { + refocusField.value = this._selectFieldValue; + } + // Restore the selection input.setSelectionRange(...this._selectFieldSelection); } } diff --git a/test/tests/itemPaneTest.js b/test/tests/itemPaneTest.js index 51887d1f36..ebfae71279 100644 --- a/test/tests/itemPaneTest.js +++ b/test/tests/itemPaneTest.js @@ -648,6 +648,27 @@ describe("Item pane", function () { await waitForNotifierEvent('modify', 'item'); assert.equal(itemOne.getDisplayTitle(), "Updated title"); }); + + it("should retain unsaved value between refreshes", async function () { + let itemOne = new Zotero.Item('book'); + await ZoteroPane.selectItem(itemOne.id); + + let itemDetails = ZoteroPane.itemPane._itemDetails; + let infoBox = itemDetails.getPane("info"); + + // Type something into the series field without saving it + let seriesField = infoBox.querySelector("#itembox-field-value-series"); + seriesField.focus(); + seriesField.value = "Series name"; + + // Trigger a refresh + infoBox._renderInternal(); + await waitForFrame(); + + // Ensure the field is still focused AND has the yet-unsaved text + assert.equal(doc.activeElement.parentNode.id, "itembox-field-value-series"); + assert.equal(doc.activeElement.value, "Series name"); + }); }); describe("Libraries and collections pane", function () {