From 4c3305783458a16ea48e6598be9068691dbd067f Mon Sep 17 00:00:00 2001 From: Juuso Ranne Date: Sat, 6 Jun 2026 19:30:13 +0300 Subject: [PATCH] Add GET /api/reader/openItems endpoint to local API --- .../zotero/xpcom/server/server_localAPI.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/chrome/content/zotero/xpcom/server/server_localAPI.js b/chrome/content/zotero/xpcom/server/server_localAPI.js index c138f2696a..2637d351aa 100644 --- a/chrome/content/zotero/xpcom/server/server_localAPI.js +++ b/chrome/content/zotero/xpcom/server/server_localAPI.js @@ -882,6 +882,43 @@ Zotero.Server.Endpoints["/api/users/:userID/tags/:tag"] = Zotero.Server.LocalAPI Zotero.Server.Endpoints["/api/groups/:groupID/tags/:tag"] = Zotero.Server.LocalAPI.Tag; +/** + * Returns the top-level items whose attachments are currently open in the reader, + * deduplicated by parent item. Used by external tools (e.g. editor plugins) to + * cite papers the user is actively reading without requiring clipboard interaction. + */ +Zotero.Server.LocalAPI.OpenReaderItems = class extends LocalAPIEndpoint { + supportedMethods = ['GET']; + + run(_) { + let seen = new Set(); + let items = []; + + for (let reader of Zotero.Reader._readers) { + let attachment = Zotero.Items.get(reader.itemID); + if (!attachment) continue; + + let parentID = attachment.parentID; + if (!parentID || seen.has(parentID)) continue; + seen.add(parentID); + + let parent = Zotero.Items.get(parentID); + if (!parent) continue; + + items.push({ + key: parent.key, + title: parent.getField('title') || '', + date: parent.getField('date') || '', + creators: parent.getCreatorsJSON(), + }); + } + + return [200, 'application/json', JSON.stringify(items, null, 4)]; + } +}; +Zotero.Server.Endpoints["/api/reader/openItems"] = Zotero.Server.LocalAPI.OpenReaderItems; + + /** * Convert a {@link Zotero.DataObject}, or an array of DataObjects, to response JSON * with appropriate included data based on the 'include' query parameter.