From 92dfac8c6445f19b2cb0343739fd0cfbd77cc663 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 4 Sep 2026 15:17:34 -0400 Subject: [PATCH] Don't make an unloaded tab reopenable with Undo Close Tab unload() closes and re-adds the tab, and the close recorded an undo-close history entry, so Undo Close Tab could open a duplicate of a tab that was still open. --- chrome/content/zotero/tabs.js | 11 ++++++++--- test/tests/tabsTest.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/chrome/content/zotero/tabs.js b/chrome/content/zotero/tabs.js index 8a1330b7c0..886441100c 100644 --- a/chrome/content/zotero/tabs.js +++ b/chrome/content/zotero/tabs.js @@ -722,8 +722,10 @@ var Zotero_Tabs = new function () { * Close tabs * * @param {String|Array|undefined} ids One or more ids, or empty for the current tab + * @param {Object} [options] + * @param {Boolean} [options.skipHistory=false] - Don't make the tabs reopenable with undoClose() */ - this.close = function (ids) { + this.close = function (ids, { skipHistory = false } = {}) { if (!ids) { ids = [this._selectedID]; } @@ -779,7 +781,9 @@ var Zotero_Tabs = new function () { } }); } - this._history.push(historyEntry); + if (!skipHistory) { + this._history.push(historyEntry); + } Zotero.Notifier.trigger('close', 'tab', [closedIDs], true); this._update(); }; @@ -990,7 +994,8 @@ var Zotero_Tabs = new function () { return; } var { tab, tabIndex } = this._getTab(id); - this.close(tab.id); + // The tab stays open, so it isn't reopenable + this.close(tab.id, { skipHistory: true }); this.add({ id: tab.id, type: `${tab.type}-unloaded`, diff --git a/test/tests/tabsTest.js b/test/tests/tabsTest.js index 3d91882c0a..8e3a1a10b3 100644 --- a/test/tests/tabsTest.js +++ b/test/tests/tabsTest.js @@ -41,6 +41,24 @@ describe("Zotero_Tabs", function() { }); }); + describe("#unload()", function () { + it("should not make an unloaded tab reopenable", async function () { + let item = await createDataObject('item'); + let attachment = await importPDFAttachment(item); + let reader = await Zotero.Reader.open(attachment.id); + let tabs = win.Zotero_Tabs; + tabs.select('zotero-pane'); + let historyLength = tabs._history.length; + + tabs.unload(reader.tabID); + + let { tab } = tabs._getTab(reader.tabID); + assert.equal(tab.type, 'reader-unloaded'); + assert.lengthOf(tabs._history, historyLength); + tabs.close(reader.tabID); + }); + }); + describe("Window teardown", function () { it("should not leave observers registered after a window is closed", async function () { this.timeout(60000);