Commit graph

54 commits

Author SHA1 Message Date
Dan Stillman
77a3a8815e Add a query syntax to the quick search
Some checks are pending
CI / Detect changes (push) Waiting to run
CI / Test () (push) Blocked by required conditions
CI / Test (macOS NFS) (push) Blocked by required conditions
CI / Test (Windows arm64) (push) Blocked by required conditions
CI / Test (Windows x64) (push) Blocked by required conditions
CI / Utilities Tests (push) Waiting to run
CI / Build, Upload (push) Waiting to run
Zotero.SearchQuery turns a query like `by:smith after:2020 tag:"to read"
crispr` or `creator is smith and (tag is foo or bar)` into a
Zotero.Search, matching whatever text is left over using the current
search mode. Anything that doesn't look like a clause is free text, so a
DOI or a title with a colon in it is matched literally.

The search box syntax-highlights the parts of recognized conditions and
offers autocomplete for condition names, for the values of conditions
that have a fixed set of them (like item type), and for tags and
creators from the selected libraries.
2026-08-20 16:09:20 -04:00
Dan Stillman
0ee3e4052e Don't prompt to save an unchanged saved search
https://forums.zotero.org/discussion/133302/zotero-10-questions-about-search
2026-08-20 15:38:13 -04:00
Dan Stillman
c87328ada9 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.
2026-08-07 11:03:57 -04:00
Dan Stillman
9da57a9fe3 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.
2026-08-05 13:14:37 -04:00
Dan Stillman
f245f5c2b2 fx153: Set XUL checked/disabled as boolean attributes
Bug 2008041 made them html-style boolean attributes, so presence alone
means true and setAttribute('disabled', false) now disables the element.
Switch the sites that can be passed a falsy value to toggleAttribute(),
read them with hasAttribute(), and drop a disabled="false" from markup.
Sites that only ever pass true are left alone.
2026-08-03 11:48:40 -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
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
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
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
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
e416ea2dfa Fix repeated save prompt after trashing the saved search being edited
Deleting a search in the collections pane moves it to the trash rather
than erasing it, so the check that closes the saved-search editor when
the edited search is deleted didn't catch it. The save-changes prompt
then appeared on the next selection change, and canceling couldn't
restore the removed row, so the prompt reappeared on every selection
until choosing Don't Save. Treat a trashed search like a deleted one
and close the editor without prompting.
2026-07-02 12:44:07 -04:00
Dan Stillman
2f364f2fab Allow creating a saved search with collections or searches selected
Previously a search could be saved only at a library root. Now the Save
Search button is enabled when collections and/or saved searches within
a single editable library are selected, and the selection is added to
the saved search as collection/savedSearch conditions -- an 'any' group
of them when more than one row is selected. If the search's own join
mode is 'any', its existing conditions move into an 'any' group of
their own so the scope conditions apply to every result instead of
joining the OR. A 'recursive' condition is included per the
recursiveCollections pref.

https://forums.zotero.org/discussion/132528/beta-cannot-create-a-saved-search-from-a-collection
2026-07-02 12:38:52 -04:00
Dan Stillman
13bd8c9d8d
Group attachment and annotation conditions into Advanced Search submenus (#5981) 2026-06-30 14:20:47 -04:00
Dan Stillman
340ba92513 Show "Search subcollections" only with a Collection condition
The option only affects Collection conditions, so hide it -- and don't
emit the 'recursive' condition -- when the search has none.
2026-06-26 16:29:34 -04:00
Dan Stillman
6c7c661fb1 Advanced search: Separate Saved Search from the Collection condition
Saved searches were folded into the "Collection" condition's value menu
in 2016 (9c52ebdf8b), for reasons I can't totally remember. Give Saved
Search its own condition again.
2026-06-26 16:24:49 -04:00
Dan Stillman
3875f411e5 Advanced search: Show binding hints and warnings on condition select
Not just on value entry, but add an exception for a new row created with
the + button

Addresses #5978
2026-06-26 15:52:34 -04:00
Dan Stillman
680452cc59 Advanced search: Update condition grouping icon and add ungroup button
Addresses #5978
2026-06-26 15:52:16 -04:00
Dan Stillman
3544848e5f Keep an edited search condition value when switching condition types
Addresses #5978
2026-06-26 15:50:58 -04:00
Dan Stillman
ccf6f18643 Prefill Advanced Search from the quick search (#5962)
Opening Advanced Search from a non-empty quick search reproduces the
current quick search mode as editable conditions, one per word (or quoted
phrase) joined with "all":

- Title/Creator/Year: a single Title, Creator, Year condition per word,
  with the result level set to item (the mode matches only top-level items)
- All Fields & Tags: a single Any Field condition per word
- Everything: Any Field + Full Text Content as an "any" group per word
  (relies on grouped full-text composing correctly in SQL)

The Title/Creator/Year mode needs a condition to map to, so add a "Title,
Creator, Year" search condition that expands to the same field set as the
quick search mode (title, publication title, short title, court, year,
citation key, creator), mirroring how Any Field matches All Fields & Tags.
Like Any Field, it expands at query-build time, so the saved search stores
a single condition and its sub-fields don't need their own entries in the
condition menu.
2026-06-25 16:14:38 -04:00
Dan Stillman
092295da22 Add result-level controls to the Advanced Search builder (#5962)
- Reword the header as one sentence with a result-level menu ("Find
  [attachments] matching [all] of the following:")
- Provide a per-group menu to bind the group's descendant conditions to
  the same attachment, note, or annotation (e.g., one annotation that is
  both red and contains a given word, not two different ones)
- Show a hint that offers to group ungrouped sibling conditions (e.g.,
  two annotation conditions at the top level, to bind them to one
  annotation)
- Show a warning when conditions can't combine at the chosen result
  level (e.g., an annotation condition with a note result level)
- Remove the two legacy checkboxes:
  - "Show top-level items" becomes result level = top-level item and is
    migrated on save
  - "Include parent and child items", which has no result-level
    equivalent, keeps working, stays editable, and round-trips on
    searches that already have it, but it isn't offered on new searches
    and is removed on save if unchecked
2026-06-25 16:14:38 -04:00
Dan Stillman
d808988540 Add condition grouping UI to Advanced Search (#5962)
Render the search as a tree of groups: a root group plus nested
search-condition-group elements, each with its own join-mode menu and a
remove control. Each condition row gets a "( )" button that wraps it in
a new group in place, so further conditions can be added to combine with
it under a separate join mode. Switch the builder to rebuild-from-tree --
the DOM is the source of truth and the search's flat conditions (with
groupStart/joinMode/groupEnd markers) are regenerated on each edit, so
the old conditionID-as-index tracking is gone.
2026-06-25 16:14:38 -04:00
Dan Stillman
8d7f5a39f9 Don't include trashed items in Advanced Search outside the trash
#5658 added includeDeleted to the Advanced Search outside the trash, so
trashed items kept matching: trashing a result removed its row, but
re-running the search brought it back. Exclude deleted items by default,
the same as a quick search, and only include them when viewing the trash,
where the scope returns only deleted items.

Fixes #5956
2026-06-19 14:07:43 -04:00
Dan Stillman
35c8448582 Advanced search: Move focus to next "-" button when removing row via keyboard 2026-06-19 00:14:06 -04:00
Dan Stillman
e37a7d8f06 Advanced search: Don't run the search on Shift-Enter 2026-06-19 00:14:06 -04:00
Dan Stillman
2e79bbe402 Advanced search: Focus condition drop-down when adding row via keyboard 2026-06-19 00:14:05 -04:00
Dan Stillman
e38f8f78b0 Advanced search: Add find-as-you-type for all conditions
Closes #5953
2026-06-19 00:14:05 -04:00
Dan Stillman
1c76195a7c Show library-aware section headers in the item tree for multi-row selections (#5954)
When multiple collection-list rows are selected, group the combined
items by library under sticky headers (e.g., "My Library", "Group X (2
collections selected)"), or show a single summary header for a multi-row
selection within one library, with blank spacer rows separating
libraries.
2026-06-18 14:09:36 -04:00
Dan Stillman
15c2c95470 Support multiple-collection selection (#5954)
Allow selecting multiple collections, saved searches, or library roots in the
collection tree -- within a library or across libraries -- and show the union
of their items. The selection is threaded through the pane as an array
(getCollectionTreeRows(), changeCollectionTreeRows(), etc.); the item pane, tag
selector, reports, and export operate on all selected rows.

Adding items (new items and notes, drag-and-drop, the attachment dialog,
import, Add by Identifier) targets every selected collection. Only rows that can
share an items view may be combined: collections, saved searches, and library
roots mix freely, and multiple Recently Read rows can be combined across
libraries, but other special views (Trash, Duplicates, etc.) and rows from
different visibility groups can't be shown together, so a selection mixing them
keeps only the focused row. In-window advanced search runs across all selected
collections.

Advanced search value autocomplete is now scoped to the searched library, fixing
a long-standing TODO where suggestions were drawn from all libraries regardless
of the search scope; for a cross-library selection it spans the selected
libraries.

For a cross-library selection, the tag selector shows the union of tags
(colored tags only when a single library is in scope, since colors are
per-library), and deleting a tag spans all selected libraries while
rename/color/split are disabled. If advanced search is open, the
collection and saved-search conditions are omitted, since each is scoped
to a single library.
2026-06-18 14:05:55 -04:00
Dan Stillman
27560d9476 Prompt for a name when saving a new advanced search
The temporary advanced search saved silently under an auto-generated
"Untitled" name. Prompt for a name instead (defaulting to that name),
and label its button "Save Search…" to signal the dialog. The saved-search
editor's button, which saves changes directly, is now just "Save".

https://github.com/zotero/zotero/pull/5658#issuecomment-4696398750
2026-06-14 15:17:25 -04:00
Dan Stillman
81b3c13b13 Close the saved-search editor when the edited search is deleted
Deleting the saved search being edited triggered onCollectionSelected's
save-changes prompt, which doesn't make sense for a search that's gone.
Detect the deleted search and close the editor without prompting.
2026-06-14 15:02:40 -04:00
Dan Stillman
8ed617ae53 Allow removing the last advanced-search condition to reset it
The remove button on the sole remaining condition is now enabled once a
value is entered, and clicking it replaces the condition with the default
empty one shown when the pane is first opened, instead of staying
disabled.
2026-06-13 19:33:31 -04:00
Dan Stillman
97aa4f93ea Restore saving advanced searches in editable group libraries
Some checks are pending
CI / Build, Upload, Test (push) Waiting to run
Regression in #5658
2026-06-13 19:21:35 -04:00
Abe Jellinek
00527332c4 Move Advanced Search and saved search editing to the main window (#5658)
---------

Co-authored-by: Dan Stillman <dstillman@zotero.org>
2026-06-12 15:21:59 -04:00
Adomas Venčkauskas
49130c71d8 Fix connector save timing out with Advanced Search
Report: https://forums.zotero.org/discussion/127760/connector-conflict-with-advanced-search

Also restore Advanced Search tests that depend on the item tree. They
were disabled due to React timing issues. Hopefully with these changes
the initialization of the tree is more robust.
2025-11-03 09:24:35 +02:00
Abe Jellinek
67d2e1cead fx140: Asyncify/ESMify tests
They seem to be succeeding when run individually, but failing when
run as a whole. Not sure why yet.
2025-07-30 22:30:53 -04:00
Dan Stillman
c1cea87743 Disable advanced search test
Completely, not just in CI, since it's failing for me locally
2025-05-09 01:41:05 -04:00
Abe Jellinek
c3e927e52f Disable flaky Advanced Search test on CI
Re-enable after we figure out #4375, but this is breaking PR CI runs
right now.
2024-07-11 11:43:23 -04:00
Bogdan Abaev
2f1aa19ae5 tweaks for tests to pass after React 18 upgrade (#4338)
- Wait for the itemsView to be initialized in the onload listener of the
  Advanced Search window
- moved waitForTagSelector in a few tests to avoid it resolving too
  early. For some tests these tweaks are always required, for others -
  tests would pass half the time. Again, not clear why it's necessary,
  potentially some flakiness from react 18?
2024-07-10 01:04:33 -04:00
Dan Stillman
7094945dff Add missing await in advanced-search test 2024-02-01 00:55:02 -05:00
Adomas Venčkauskas
32ba987c28 Fix failing Advanced Search test (regression 172fe371) 2023-12-12 18:14:19 +02:00
Dan Stillman
b99e581929 Fix advanced-search tests 2023-04-15 00:24:02 -04:00
Abe Jellinek
8face792c0
fx-compat: Fix search dialogs (#2631) 2022-07-04 01:48:52 -04:00
Dan Stillman
045f1fbb7e Add utility functions for building drop-down library lists
A XUL one for the current use in Advanced Search and an HTML one for
future uses. Sets the value to libraryID and adds data attributes for
editable/filesEditable on the HTML one.
2017-12-08 00:42:03 -05:00
Dan Stillman
820755e152 Rework libraryTreeView event handling
Changes `libraryTreeView::addEventListener('load')` and similar to
`libraryTreeView::onLoad.addListener(listener, once)`, etc. `once` is an
optional boolean that, when true, causes the listener to fire once and
then be removed. This is implicit for 'load'.

'load' maintains its special behavior of running immediately if the
treeview has already been loaded.

Also adds `waitForLoad()` and `waitForSelect()` functions that return
promises on event completion, since most uses of those events were just
resolving deferreds.
2017-03-24 05:23:56 -04:00