Commit graph

2072 commits

Author SHA1 Message Date
Maximilian Schmidt
a1be174c28 Fix zero local data object versions (#6016)
(cherry picked from commit b8fdee865a)
2026-08-13 11:23:49 -04:00
Dan Stillman
443a5825ba Fix leading space in creator autocomplete values
the all-creators mode (fieldmode 2) concatenated
firstname || ' ' || lastname, so a two-field creator without a first
name produced ' last', which advanced search fields inserted with the
space.

(cherry picked from commit c87328ada9)
2026-08-07 11:04:50 -04:00
Dan Stillman
ec5419f80e Search: Allow binding a group whose conditions match at any level
Binding is meaningful for a condition that matches at every level -- a
tag bound to an attachment means the tag is on the attachment -- but a
group carrying one lost the binding as soon as the search was
serialized, so "items with an attachment tagged foo" couldn't be built.

(cherry picked from commit 9da57a9fe3)
2026-08-05 15:15:03 -04:00
Adomas Venčkauskas
9c03a93e00
Fix tree multi-selection collapse/expand behaviour (#5983)
Closes #5974.

Additional fixes for broken item tree behaviour when multiple items are
selected, and changing focus with ctrl/cmd-arrow keys.

Aligned Collection Tree/Virtualized Tree collapse/expand behaviour when
multiple containers are selected, one of them is focused, and arrow key
left-right is pressed, to the behaviour in Item Tree - now all of them
are collapsed/expanded.

---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-07-31 13:25:01 -04:00
Martynas Bagdonas
a7cae87be8
Improve undo/redo in the note editor (#3398)
- Fix "redo" command not enabled in the note editor
- Centralize note editor undo and redo commands
- Update note editor submodule

Co-authored-by: Tom Najdek <tom@doppnet.com>
2026-07-31 14:22:53 +02:00
Dan Stillman
7abcf23ef7 Move PMC lookup after open-access lookup
The PMC lookup in #5906 was added before the OA lookup, but the OA
lookup often returns a PMC URL of its own (including, at least now, for
the DOI given in the PR), with a direct file URL rather than a page to
scrape, so try it first and fall back to the PMCID-derived URL only when
it turns up nothing.
2026-07-30 20:56:28 -04:00
Dan Stillman
8bebaf0ead Fix open-access lookup for PMCID items during in-app translation
Since #5906, the 'oa' resolver list can start with a plain URL object
for items with a PMCID, but _getOpenAccessPDFURLs() and
saveOpenAccessAttachment() called resolvers[0](), which threw for those
items -- skipping the lookup silently in the first case and failing the
save in the second.
2026-07-30 20:55:16 -04:00
Dan Stillman
9ed00c843d Don't update read status when using Show File
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Show File triggered a file 'open' notification, so revealing a file
moved its item to the top of Recently Read. Use a separate 'reveal'
event, which file syncing still observes to queue a modification check.

https://forums.zotero.org/discussion/133006/
2026-07-30 13:43:41 -04:00
Tom Najdek
c39f16891f Extend the template engine and add template validation (#5989)
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
- Fix multiple potential scenarios causing a template engine crash
 - Add support for specifying string literals in the template engine
 - Validate `if/else/elseif` order and matching clause closures
 - Validate to ensure every `{{` is properly closed with a matching `}}`
 - When a template is invalid, display a warning, do not offer batch-renaming tools, do not update synced setting
 - When a template is invalid, prompt the user to fix or reset the template when

Closes #5965
2026-07-29 13:30:12 -04:00
Tom Najdek
efcfaec5d4 Move templating engine to a standalone, lazy-loaded module (#5989) 2026-07-29 13:30:03 -04:00
Dan Stillman
dc6d55a137 Remove collectionTreeRow from the plugin menu context
Menu plugins reading it acted on one arbitrary row of the selection.
Reading it now throws and names collectionTreeRows, which the context
has already provided since multi-collection selection landed.

The context now copies property descriptors rather than values, since
copying values would evaluate the throwing collectionTreeRow getter for
every menu.
2026-07-29 13:22:58 -04:00
Dan Stillman
783da0e66e Don't offer Remove from Collection if saved search is selected
Collections and saved searches can be selected together, and the
search's items don't need to be in any of the collections, which would
result in search-only items being moved to the trash.
2026-07-29 13:12:47 -04:00
Dan Stillman
1d97f6448e Replace ItemTree#collectionTreeRow with a validated view mode
The view-wide branches (trash, duplicates, feeds, Recently Read) read
the first selected row, which multi-collection selection preserved with
a getter rather than updating. setCollectionTreeRows() now derives the
kind of view the selection adds up to, throwing if the rows disagree,
and those branches test it.
2026-07-29 13:12:47 -04:00
Dan Stillman
5d1a2cba32 Remove the singular collection tree selection getters
Multi-collection selection left .collectionTreeRow and similar in place
to reduce breakage, but that would just leave plugins and other callers
potentially broken when multiple rows were selected. All singular
getters now throw and say what to use instead. getSelectedLibraryIDs()
was added to replace getSelectedLibraryID().
2026-07-29 13:12:47 -04:00
Dan Stillman
e45871fa9d Don't treat a selected saved search as a collection
Collections and saved searches can be selected together, so a
collection-item change called getDescendents() on rows that don't have
it and compared search IDs against collection IDs.
2026-07-29 12:55:41 -04:00
Dan Stillman
c92c75eb36 Mark read attachments in every selected library
Recently Read rows can span libraries, but read attachments were marked
as matches for the first row's library only, leaving the rest as grayed
context rows.
2026-07-29 12:55:40 -04:00
Dan Stillman
3da869b2e6 Keep library headers in place when the items list is re-sorted
Header and spacer rows stayed in the row list during a sort and were
ordered as if they were items, so a column sort could move them out of
position.
2026-07-29 11:33:15 -04:00
Dan Stillman
85a33e1586 Don't treat library header and spacer rows as items
Code walking the items list assumed every row was an object, so the
headers and spacers shown whenever more than one row is selected got
picked up as items: getSortedItems() passed them to export and report
generation, restoring from the trash called item methods on them, and
the item pane counted them in "N items in this view".
2026-07-29 11:33:14 -04:00
Dan Stillman
ae98136ec8 Save uploaded objects to the sync cache on an unchanged response
The cache-existence check didn't await getCacheObject(), so the
promise was always truthy and no cache object was ever saved for
objects the server reported as unchanged. Without a cached version,
later remote changes to those objects produced avoidable conflicts.
2026-07-29 00:06:42 -04:00
Dan Stillman
2fb8d69a93 Auto-resolve lastRead conflicts without a cached version
lastRead conflicts were auto-resolved only when a cached version of
the object was available, so differing read times could still trigger
the conflict resolution window.
2026-07-28 23:56:29 -04:00
Abe Jellinek
681c48f1c2 Local API: Don't validate Zotero-Server-ID for file uploads
Some checks are pending
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
https://github.com/urschrei/pyzotero/issues/344#issuecomment-5108140508
2026-07-28 12:34:40 -06:00
Dan Stillman
caeffa9f41 Citation dialog: Hide the citation preview until the citation has items
Show the preview area and its toggle button only once there is
something to preview, instead of showing a "Preview" placeholder in an
empty dialog.
2026-07-28 12:29:59 -04:00
Dan Stillman
7925b4e9ac Citation dialog: Add all selected items on + click in Library mode
Clicking the + button on a row that is part of a multi-item selection
now adds all selected items to the citation, matching the existing
list-mode behavior. Clicking + on an unselected row still adds only
that item.
2026-07-28 12:16:41 -04:00
Dan Stillman
93d66e3999 Citation dlg: Don't enter locator-typing mode after adding multiple items
With focus moving back to the input after a multi-item add, a typed
number was applied as a page locator to every just-added item. It now
starts a search instead. Single-item adds still enable the typed-locator
shortcut.
2026-07-28 12:16:11 -04:00
Dan Stillman
938c414e0c Citation dialog: Fix post-add scroll crash that left focus in the items list
_scrollItemTreeToRow() parsed the row index from the wrong rowID
segment, so it threw on every call, and adding items from the items list
never returned focus to the input as intended.
2026-07-28 12:16:01 -04:00
Abe Jellinek
a37a9e782a Add Zotero-Server-ID, require for writes, validate when provided
Every local API response includes a stable per-database server ID so
that clients can partition cached data, especially local object
versions, by Zotero instance. Write requests must include the ID, and
when it's provided on any request it must match the current server.

---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-07-28 09:57:44 -04:00
Abe Jellinek
77f2432103 Local API: Support write requests
Add support for item, collection, and search writes (POST/PUT/PATCH/
DELETE), tag deletion, full-text writes, and the three-phase file
upload flow. Writes require a local API key granted by the user via a
confirmation dialog (POST /api/local/authorize) and follow the web
API's concurrency model, with If-Unmodified-Since-Version and
per-object version preconditions checked against local versions.

---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-07-28 09:57:44 -04:00
Abe Jellinek
9dd17a212e Track data object versions locally
Add a clientVersion column for items, collections, searches, and
libraries, incremented once per library per transaction on every
object save or deletion. The local API reports these versions instead
of synced versions -- in object JSON, format=versions, since=
filtering, and Last-Modified-Version -- since synced versions don't
reflect local changes and are 0 for unsynced objects. Group metadata
responses keep reporting the synced group version, which has no local
counterpart.

---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-07-28 09:57:43 -04:00
Dan Stillman
12114f6a86 Fix binary file corruption in multipart/form-data parsing
_decodeMultipartData() trimmed each part body, mangling file content that
begins or ends with a whitespace byte (e.g., a PDF ending in a newline).
2026-07-28 09:57:43 -04:00
Dan Stillman
512a2444d8 Add timeout to HiddenBrowser::getPageData()
The queries wait for the document to be ready, so a page that never
finished loading would hang the caller -- e.g., full-text indexing --
forever.
2026-07-24 13:11:50 -04:00
Dan Stillman
9eea7d9a0c Disable JavaScript when indexing HTML files
Page scripts otherwise run during indexing and can hang it. JavaScript
was disabled here in 2a7f31813e for the same reason, but that was lost
in the fx-compat rewrite (13adfd131c).

https://forums.zotero.org/discussion/132901/
2026-07-24 13:11:50 -04:00
Dan Stillman
3a54a5ecb1 Fix allowJavaScript option in HiddenBrowser
allowJavaScript: false didn't disable scripts for a system-principal
document, such as a blob: URL created from chrome code, which runs
scripts regardless of the allowJavascript flag. Sandbox the document
instead, forcing a null principal and blocking script execution.
2026-07-24 13:11:50 -04:00
Dan Stillman
a81af0c268 Don't show Extra migration progress window unnecessarily
The candidate scan counted items whose Extra content parsed as fields
but couldn't actually be migrated (e.g., fields already set on the
item), so the window could appear on every global schema update without
changing anything.

Also use a dedicated headline instead of "Upgrading database…", and show
the window only if the migration is still running after 500 ms.
2026-07-23 23:21:01 -04:00
Martynas Bagdonas
ea4b301f73 Avoid SDT test fixture updates on version bumps
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
2026-07-23 20:24:21 +03:00
Dan Stillman
4f825ad50c Don't throw getting the filename of a stored file with a corrupt path
A stored file's path is normally 'storage:<filename>', which is parsed
as a string, but some ancient libraries apparently have relative paths
('../.../foo.pdf') that fell through to PathUtils.filename() and threw
NS_ERROR_FILE_UNRECOGNIZED_PATH, breaking syncing.

Resolve stored-file leaves as strings regardless of prefix and reserve
PathUtils.filename() for linked files, whose paths are genuine absolute
paths.

https://forums.zotero.org/discussion/132861/zotero-sync-issue-id-1987012678
2026-07-23 11:12:12 -04:00
Dan Stillman
a4b39b91f3 Exclude trashed items from tag autocomplete suggestions
https://forums.zotero.org/discussion/132875/some-tag-suggestions-appearing-capitalised
2026-07-22 11:46:52 -04:00
Dan Stillman
146520aed5 Reload quick search when changing the search mode
Changing the quick-search mode dropdown didn't re-run the current
search, since the filter was applied without a mode and the unchanged
search text made setSearch() report no change.

Regression from 5ca1fbb167

https://forums.zotero.org/discussion/132873/beta-quick-search-isnt-reloaded-when-changing-search-mode
2026-07-22 11:14:23 -04:00
Dan Stillman
cddb19bf36 Only reject and strip actual directory paths in stored-file filenames
Some checks are pending
CI / Test (shard 1) (push) Waiting to run
CI / Test (shard 2) (push) Waiting to run
CI / Test (shard 3) (push) Waiting to run
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
ee68452b treated any backslash as a directory separator, in both the
attachmentPath setter and the userdata 128 migration. But backslashes
are technically valid on Linux/macOS and appear in real filenames (due
to LaTeX in titles, etc.), so that would wrongly throw on or truncate
them. Only a forward slash (never valid in a filename) or a Windows
absolute path (drive-letter or UNC prefix) reliably indicates a leaked
directory path, so treat just those as paths and leave bare backslashes
alone. We should make sure we're running getValidFileName() everywhere
to avoid saving those.
2026-07-21 16:02:40 -04:00
Dan Stillman
e81e72dccf Fix negated Title/Creator/Year and Any Field advanced searches
These conditions expanded into an OR-group across their underlying
fields, so a "does not contain"/"is not" operator matched almost every
item: any item missing one of the fields satisfied that field's negated
condition. Use an AND-group for negative operators, so the value must be
absent from every field.

https://forums.zotero.org/discussion/132835/
2026-07-21 14:15:45 -04:00
Dan Stillman
40974e493d Fix Cmd/Ctrl-A not selecting all libraries when feeds are visible
Selecting all libraries pulled in feed rows, which belong to a different
visibility group and so can't be shown together, collapsing the
selection back to a single row. Constrain the all-libraries scope to the
current selection's visibility group. Also preventDefault() the shortcut
so it no longer falls through to the cmd_selectAll key command, which
threw NS_ERROR_FAILURE.

https://forums.zotero.org/discussion/132843/beta-cannot-select-all-libraries
2026-07-21 14:04:00 -04:00
Dan Stillman
621c0fbb91 Fix storageLocal test broken by ee68452b0
The download-rename test used a backslash as its sample invalid
character, which now throws in the attachmentFilename setter. Use a
colon instead, which still tests download-time filtering.
2026-07-21 11:08:42 -04:00
Dan Stillman
ee68452b05 Disallow slashes in stored-file attachment paths
Someone ended up (via a plugin, presumably) with stored-file attachments
with a full path after 'storage:', which broke file syncing. Throw when
setting a stored-file path containing a slash, and strip paths from
existing filenames in a schema update step. No particular reason to
think that the file with that basename will exist in the storage dir,
but at least it will be looking for the right file and not be totally
broken.

Separately, the dataserver will clean up filenames with full paths and
block going forward.

https://forums.zotero.org/discussion/132822/reference-sychronization-error
2026-07-21 10:40:59 -04:00
Dan Stillman
5877952954 Add accented stop-words to abbreviations word list
Accented stop-words weren't matched by the existing unaccented
entries (e.g., "fur"), so automatic journal abbreviation kept and
capitalized them: "Jahrbuch für Heimatkunde" became "Jahrb. Für
Heimatkunde" instead of "Jahrb. Heimatkunde".

https://groups.google.com/g/zotero-dev/c/uP18QEKe2JU/m/AsoGWxd9AwAJ
2026-07-20 22:52:51 -04:00
Dan Stillman
59c1801a10 Fix looping re-extraction of full-text queue items with no text
If a queued attachment was missing its cache file and re-extraction
produced no text, nothing was recorded in the index state, so the
content-index queue selected the same items forever and the startup
drain never finished.

https://forums.zotero.org/discussion/132808/
2026-07-18 14:33:13 -04:00
Martynas Bagdonas
c233fcf5f0 Fix reopening reader tabs during queued close notifications
Fixes https://forums.zotero.org/discussion/comment/515471/#Comment_515471
2026-07-17 20:11:49 +03:00
Dan Stillman
bcfa43b7e9 Fix routing of search terms mixing CJK and non-ASCII words
A term mixing CJK with non-ASCII words (e.g., Cyrillic plus Japanese)
was routed to the CJK index with only its CJK characters, matching
every document that contained those. Treat any non-CJK letter or digit
as making a term mixed-script, which falls back to a literal scan of
the cached text.
2026-07-17 12:41:30 -04:00
Dan Stillman
0ce289a7fe Use a word index for full-text content search
Replace the trigram FTS5 index for attachment content with a unicode61
word index, so terms match whole words with the final token as a prefix
("archive" matches "archives", but "ion" doesn't match "condition"), as
in the pre-FTS5 word index. A multi-word phrase gets adjacent-token
candidates from the index and is then verified against the cached text
of just those items, since FTS5 ignores what separates adjacent tokens;
the verification treats whitespace and hyphen runs as equivalent
(they're frequently extraction layout or styling) but requires other
punctuation to match literally. Notes keep the trigram index and CJK
matching is unchanged; the index database version is bumped so the
index is rebuilt.

Follow-up to #5979
2026-07-17 12:41:19 -04:00
Dan Stillman
fb20a84ab7 Handle stale WAL files in corrupted-database recovery
SQLite replays a leftover -wal file (e.g., from a force-quit) into
whatever file next occupies the database path, so copying a backup
over zotero.sqlite produced a corrupted-database error, and the
automatic restore recreated the same mismatch and failed every time.

When corruption is detected, check if the database file is valid without
its journal files, and if so, save a verified copy and restart, swapping
the copy in at the next startup before the database is reopened. (The
copy is made before shutdown because SQLite automatically checkpoints
the WAL into the database file when the last connection closes, which
would write the stale WAL data into the file.) Otherwise, move journal
files along with the .damaged file to clear them from the main path
before restoring from the automatic backup or creating a new database.

Since a mismatched WAL can cause subtle data damage without errors, also
run a full integrity check at startup after an unclean shutdown. Skip
the explicit close-time WAL checkpoint once corruption has been flagged,
and truncate the WAL during idle maintenance to limit stale WAL data.
2026-07-16 11:43:31 -04:00
Dan Stillman
a2c7e0c00e Support saving and restoring main-window progress meter state
showZoteroPaneProgressMeter() now returns a token capturing the
previous message, meter mode and position, and owner, and
restoreZoteroPaneProgressMeter() restores that state if no other
operation has changed the display since, with nested tokens restoring
in reverse order.
2026-07-16 11:43:31 -04:00
Dan Stillman
6c5d160895 Fix citing and locale selection for locales without a CSL locale
The CSL locales repository replaced locales-sr-RS.xml with script
variants, so citing with a stored or default 'sr-RS' locale loaded no
terms and failed with an et-al error. Resolve unavailable locales to
the closest available CSL locale (sr-Cyrl-RS for sr-RS) when rendering
and in locale selectors.

https://forums.zotero.org/discussion/comment/515598/#Comment_515598
2026-07-16 11:28:21 -04:00