Commit graph

16674 commits

Author SHA1 Message Date
Dan Stillman
ae46954167 Add DBConnection.loadExtension()
Load a bundled SQLite extension (e.g., FTS5) by name. mozStorage
disables generic extension loading but allows specific bundled ones.
Extensions are registered per connection, so a loaded extension is
remembered and re-loaded automatically after a reconnect, before
onConnect() callbacks run.
2026-07-15 15:36:40 -04:00
Dan Stillman
da88c63231 Make the collection tree filter accent-insensitive
Addresses #1300
2026-07-15 15:36:40 -04:00
Dan Stillman
984c0a7f8c Make the tag selector filter accent-insensitive
Addresses #1300
2026-07-15 15:36:40 -04:00
Dan Stillman
3bd8d641b8 Make item search accent-insensitive
Search now ignores accents, so "seance" matches "séance" and vice versa.

Text is normalized with Unicode NFKD compatibility decomposition (which
also handles typographic ligatures, superscripts, full-width forms,
etc.) plus a small map for letters NFKD leaves alone (ø, œ, æ, ß, ...)
and the fraction slash, via Z.Utilities.Internal.normalizeForSearch().
The HTML tags we support in item fields are stripped, so markup isn't
matched (#81). Typographic quotes (#29, #1876) and dashes are folded to
ASCII.

Each searchable column gets a normalized shadow column --
itemDataValues.valueNormalized, tags.nameNormalized,
creators.firstNameNormalized/lastNameNormalized, and
itemAnnotations.textNormalized/commentNormalized -- populated at write
time and matched via COALESCE(normalized, raw) LIKE. NULL is stored when
normalizing only changes case, so plain-ASCII values are only stored
once. This covers the contains/doesNotContain/beginsWith operators in
both quick search and Advanced Search.

The new columns are local-only derived data and aren't synced. Older
clients will ignore them, so this doesn't break DB compatibility.
Existing rows are backfilled after the startup sync by
Zotero.Schema.populateNormalizedSearchColumns(), which should only take
a few seconds on most databases.

Closes #29, #81, #1300, #1876
2026-07-15 15:36:40 -04:00
Dan Stillman
d0f8d438b5 Clarify naming of the full-text sync content processor
Rename the sync-delivered full-text content processor's methods and
state to "sync content" (registerSyncContentProcessor,
processSyncedContent, indexSyncedContent, getSyncedContentCacheFile,
etc.), so it reads distinctly from the local index-building queues added
for content search. No behavior change.
2026-07-15 15:36:40 -04:00
Dan Stillman
cf09a0547c Regenerate SDT test pack fixture for pdf processor version 3
The document-worker bump raised SDT_PROCESSOR_VERSIONS.pdf from 2 to 3,
so the test's "valid" pack fixture (embedding version 2) was rejected as
stale-processor during generation, failing "should generate the pack when
missing."
2026-07-15 15:01:22 -04:00
Dan Stillman
c6595d6456 Update CSL locales 2026-07-15 13:08:36 -04:00
Dan Stillman
4f45db5009 Update translators submodule 2026-07-15 12:52:54 -04:00
Dan Stillman
933e207013 Update document-worker submodule 2026-07-15 12:52:00 -04:00
Dan Stillman
0ba89211ce Fix race between lastRead update and content-type fix on file open
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
viewAttachment() fired the 'open' notification before launchFile() saved
a sniffed content type, so AttachmentReadObserver's concurrent lastRead
save could reload the item and discard the pending change, leaving the
attachment with a blank or incorrect content type.
2026-07-14 14:01:07 -04:00
Dan Stillman
bdea584a17 Update LibreOffice submodule 2026-07-14 13:39:07 -04:00
Dan Stillman
1a5e32a7b6 Update document-worker submodule 2026-07-14 11:05:43 -04:00
Dan Stillman
142f77b094 Update reader submodule (SDT) 2026-07-14 11:05:29 -04:00
Dan Stillman
6e35bd1497 Focus the pane window before the focus traversal tests
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
The #focus() Tab/Shift-Tab tests wait on focus/blur events, which fire
only while the window is active. It intermittently loses activation in
CI's Xvfb, so call win.focus() in beforeEach when the window isn't
active.
2026-07-13 17:28:00 -04:00
nexdep
2c6185d8f1
Add Attachment Storage Type search condition (#5875)
---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-07-13 15:57:37 -04:00
Dan Stillman
89880e3284 CI: Record which test drops the main window's activation
Temporary diagnostic for the intermittent shift-tab focus-test timeout.
A central afterEach in runtests.js tracks when
Services.focus.activeWindow stops being the main window; the shift-tab
test logs the last-active and first-inactive test in its timeout
message, to identify what leaves the pane inactive in CI.
2026-07-13 15:27:39 -04:00
Dan Stillman
5a8badae7b Revert "Activate window in focus traversal tests, fixing intermittent timeouts"
This reverts commit 03a610e696.

activate() foregrounds a window via the window manager, which CI's Xvfb
doesn't have, so activateZoteroPane() in beforeEach just hangs there
instead of fixing anything. Restore the temporary open-window logging to
try to catch what leaves the pane window inactive.
2026-07-13 15:15:13 -04:00
Dan Stillman
28867883a1 Don't let embedded note images match searches in the items list
An image pasted into a note is stored as a hidden attachment, so a
matching search condition (e.g., "# of Tags" is 0) would pull the
image's parent item into the results with no visible match.
2026-07-13 14:32:40 -04:00
Dan Stillman
cdb9134537 Add "# of Notes", "# of Attachments", and "# of Annotations" search conditions
Notes and attachments are counted on regular items, and annotations on an
attachment or across a regular item's attachments; other rows are excluded
rather than always matching with a count of 0. Trashed children aren't
counted.
2026-07-13 14:18:59 -04:00
Dan Stillman
7cdd74bd2b Add "# of Tags" advanced search condition
Closes #158
2026-07-13 13:38:22 -04:00
Dan Stillman
24fe50cfd5 Add "is empty"/"is not empty" advanced search operators
Available for text, date, and number fields and creators. Previously only
possible via a doesNotContain hack with an empty value.
2026-07-13 13:38:22 -04:00
Dan Stillman
c181aac7f6 Citation dialog: Fix grouping of selected and open items
The front-most tab's item appeared under Selected Items instead of Open
Documents, and the library tab's actual selection wasn't shown. Selected
Items now always reflects the item tree selection, and an item that's both
selected and open stays under Open Documents (sorted after the front-most
tab) so that suggestions specific to open documents (e.g., the current page
number, planned in #6001) can apply to it. Notes open in tabs now appear
under Open Documents when adding a note.
2026-07-13 11:41:19 -04:00
Dan Stillman
582333397d Citation dialog: Allow typed locator after Cmd/Alt-Tab away and back
https://forums.zotero.org/discussion/132673/
2026-07-12 18:40:06 -04:00
Dan Stillman
5fe4c901ed Update stale downloadUpdate() usage in update dialog
Some checks failed
CI / Test (shard 1) (push) Has been cancelled
CI / Test (shard 2) (push) Has been cancelled
CI / Test (shard 3) (push) Has been cancelled
CI / Test (shard 4) (push) Has been cancelled
CI / Utilities Tests (push) Has been cancelled
CI / Build, Upload (push) Has been cancelled
downloadUpdate() is now async, takes a single argument, and returns a
result code rather than a state string, so the "failed" check could
never match.
2026-07-10 15:49:19 -04:00
Dan Stillman
8eb71a588d Fix download progress in update dialog
nsIProgressEventSink's onProgress()/onStatus() no longer take a context
argument.

Fixes #3130
2026-07-10 15:49:18 -04:00
Dan Stillman
dea2fb8491 Fix build_for_deploy dying silently on an empty incrementals file 2026-07-10 15:26:52 -04:00
Dan Stillman
6225931f93 Clear the quick search from every selected collection when prefilling
Opening the Advanced Search from the quick search cleared the search
text only on the first selected row, while the quick search had applied
it to all of them, so with a multi-collection selection the other
collections stayed filtered by the now-invisible text -- both while the
advanced search was open and after closing it.
2026-07-10 11:45:29 -04:00
Dan Stillman
540735785d Prompt before discarding saved-search edits via the Advanced Search toggle
With the saved-search editor open, Cmd/Ctrl-Shift-F replaced it with the
temporary Advanced Search pane and the search field's close button
closed it, in both cases discarding the editor's working copy with no
way to recover the edits. Move the collection-switch save prompt into a
shared helper and show it before replacing or closing the editor.
Choosing Save on a collection switch now continues the switch directly
instead of relying on the save's modify notification to re-sync the view.
2026-07-10 11:45:29 -04:00
Dan Stillman
4188ef0ebc Don't drop an annotationAuthor value while its author menu is loading
onConditionSelected() populates the Author value menu asynchronously,
and until it finished, the row's default textbox was still the visible
value control, so serializing the row (running or saving the search)
replaced the loaded author with an empty value. Serialize the stored
value while the menu is pending, and invalidate the population if a
newer condition selection takes over meanwhile.
2026-07-10 11:45:29 -04:00
Dan Stillman
ccc7d0a5ad Fix focus target when a keyboard removal prunes a group
removeRow() remembered the removed row's index within its own group,
but when the removal emptied the group and pruned it, the index was
applied to the ancestor's children, focusing an unrelated row. Track the
pruned group's slot in its parent instead.
2026-07-10 11:45:29 -04:00
Dan Stillman
3a34c6a18f Run a focused button's action on Enter in Advanced Search
The pane-level Enter handler ran the default action (save in the saved
editor, submit in the temporary pane) regardless of the event target, so
Enter with focus on the Cancel button saved and closed the editor, and
Enter on Clear ran the search. Click the focused button instead, which
the platform otherwise only does for Space.
2026-07-10 11:45:29 -04:00
Dan Stillman
a6c3ad51ef Keep a group's same-entity binding visible when it no longer qualifies
The "in the same annotation" binding menu was hidden as soon as a group
no longer had two conditions at the bound level, but the group's stored
binding was still saved and applied. After switching one of two bound
annotation conditions to another type, the group looked like a plain
"Match all of the following" group but still required a single
annotation to satisfy all of its conditions, and no control was left to
see or clear the binding.

Show the menu whenever the group is bound, drop the binding only once no
condition at its level remains, and refresh the menus before
collectGroup() in updateSearch() so the first save after such an edit
doesn't serialize stale state.
2026-07-10 11:45:28 -04:00
Dan Stillman
1e0cf49a16 Don't refresh the items list when clearing an unset advanced search
setAdvancedSearch() invalidated the row unconditionally, unlike
setSearch()/setTags(), so merely opening or closing the Advanced Search
pane (which applies a null filter) re-queried and rebuilt the items
list. A passed search is still always applied, since its conditions may
have been edited in place, and setFilter() still waits for a refresh
already in flight so that callers see the settled view.
2026-07-10 11:45:28 -04:00
Dan Stillman
cc28fad6da Roll a standalone attachment's annotations up to the attachment itself
_rollUpAnyToLevel() only followed an annotation's parent when the
attachment itself had a parent, so in a search for top-level items, a
tag on a standalone attachment's annotation matched nothing.
2026-07-10 11:45:28 -04:00
Dan Stillman
d95d8f294d Fix serialization of the result level seeded for a migrated childNote
The condition seeded by _loadConditions() used `mode: undefined`, but
toJSON() only omits the "/mode" suffix when the mode is exactly false
(what parseCondition() returns), so a saved search migrated from the
obsolete childNote condition serialized -- and synced -- the condition
as "resultLevel/undefined".
2026-07-10 11:45:28 -04:00
Dan Stillman
c43f028c96 Remove dead code left over from the Advanced Search dialog
onLibraryChange() has no callers since library changes re-render the
pane, and .active/doCommand() belonged to the removed dialog's search
box.
2026-07-10 11:45:28 -04:00
Dan Stillman
8daed576ba Make first top-level joinMode win in combineConditions()
_buildQuery() already uses the first top-level joinMode for the
full-text post-filter; with multiple top-level joinMode conditions (only
creatable via the API), combineConditions() used the last.
2026-07-10 11:45:28 -04:00
Dan Stillman
2c62010c4c Fix misplaced comma 2026-07-10 11:45:28 -04:00
Abe Jellinek
0a67f4967c Read Aloud: Update skip button tooltip text
#5998
2026-07-10 11:17:23 -04:00
Abe Jellinek
64165eabf6 ItemTree#selectItems(): Clear advanced search if item doesn't match
Some checks are pending
CI / Test (shard 4) (push) Waiting to run
CI / Utilities Tests (push) Waiting to run
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 / Build, Upload (push) Waiting to run
Extends existing handling for tag selection and quicksearch to handle
advanced search as well.

Fixes #5996 (not just for zotero://select but for all selectItems()
callers)
2026-07-09 14:11:36 -04:00
Dan Stillman
243ef0e28f Fix historical comments from 606d8f19ba 2026-07-09 13:12:43 -04:00
Dan Stillman
606d8f19ba Advanced search: Indent subcollections in Collection condition menu
Instead of just prefixing the labels with "-", indent the whole row,
including the icon. This looks better and fixes FAYT on subcollection
names.

https://forums.zotero.org/discussion/132561/
2026-07-09 13:09:24 -04:00
Dan Stillman
03a610e696 Activate window in focus traversal tests, fixing intermittent timeouts
The #focus() Tab/Shift-Tab tests dispatch synthetic keydowns and wait on
a focusin event to sync with the collections search field's async
(setTimeout) focus. Gecko only fires focus/blur events while the window
is active, so when the pane window wasn't active -- it opens in the
background on macOS/Windows and can lose activation on Linux/CI -- the
focusin never fired and the test hung until Mocha's timeout. Activate
the window in beforeEach, as the item pane and tags box focus tests
already do.

Also removes the temporary open-window logging added in e1f19f34f5.
2026-07-09 11:00:24 -04:00
Dan Stillman
c3787495cc Don't show empty-library message for empty search with no groups
hasItems() also now short-circuits with LIMIT 1 rather than counting all rows

https://forums.zotero.org/discussion/132635/zotero-beta-empty-database-message-when-no-results
2026-07-09 10:38:43 -04:00
Dan Stillman
e1f19f34f5 CI TEMP: Debugging for shift-tab focus test timeouts 2026-07-09 10:32:53 -04:00
Dan Stillman
1c9bf88888 Unpack update archives for different architectures in parallel
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-08 12:10:46 -04:00
Dan Stillman
39a1c56f6c Cache update diffs and compressed files across builds
Cache patches and compressed files by content hash so that they're reused
across FROM versions and releases. Cache entries are touched when used and
expire after 60 days.

The cache key includes a tag covering the xz/mbsdiff versions and the
compression options, so entries are invalidated when the toolchain changes.
2026-07-08 12:10:45 -04:00
Dan Stillman
d07dd66c21 Parallelize update MAR generation
Run the per-file mbsdiff/xz work in make_incremental_update.sh and
make_full_update.sh through a parallel job pool, largest files first, and
assemble the manifests serially afterward, producing byte-identical MARs.

Set UPDATE_PACKAGING_JOBS to override the number of parallel jobs.
2026-07-08 12:10:45 -04:00
Dan Stillman
3ae3bd41dc itemPaneTest: Scroll to attachments pane instead of relying on pin
The pinned pane doesn't reliably trigger a render of an out-of-view pane in
this state, so scroll to the pane the way the surrounding tests do.
2026-07-08 10:50:32 -04:00
Dan Stillman
4314494455 Include callback source in waitForCallback timeout errors
The stack for these errors is stripped as internal frames, so the error
didn't indicate which wait timed out.
2026-07-08 10:50:32 -04:00