The shims from 5697ee0af7 keep old plugins working for users, but
beta/dev/source builds should still throw to get the attention of
developers and (hopefully breakage-tolerant) beta users.
Status messages were left aligned for the multi-paragraph intro text,
but in a narrow window, that made single lines that wrapped sit
off-center, so center those instead.
Plugins written for earlier versions call methods like
CollectionTree#getSelectedSearch(), which now throw. We did this
intentionally to make old code more obviously broken, even with single
selection, so developers would fix their code, but we're not yet
blocking plugins that illegitimately declared compatibility with a
future version, so some haven't been updated and are breaking Zotero.
With a single row selected, the pre-10 functions can technically
continue to work, so for now, restore them and just warn and name the
plugin instead of throwing. They still need to throw if multiple rows
are selected, since plugins that haven't been updated can't safely act
on a selection that might span collections or libraries.
https://forums.zotero.org/discussion/133565/
A plugin that monkey-patches a method in the item list's load path --
say, Zotero.CollectionTreeRow.prototype.getItems() -- can throw and
leave the pane showing only "Error loading items list", with nothing in
the error report to identify it. Update the message to name the culprit.
https://forums.zotero.org/discussion/133565/
The row values were computed with `row.isItem && …`, so collection and
search rows in the trash got the boolean `false`, which the table then
rendered as the text "false".
https://forums.zotero.org/discussion/133560/
Zotero.Session.save() runs from a quit-application-granted observer
registered before the database checks, but session.json is only read
after them, so a startup error -- an incompatible database from a newer
version, say -- meant that quitting overwrote the file with an empty
state and all open tabs were lost.
https://forums.zotero.org/discussion/133542/
A stored-file path of 'storage:/' -- left behind by the 128 schema step,
which skipped paths with no basename -- triggered an
NS_ERROR_FILE_UNRECOGNIZED_PATH that aborted the whole
checkForUpdatedFiles() loop, so no files synced in the library. Skip an
attachment that throws instead of failing the whole library.
Also apply the setter's directory-path rule in getFilePath[Async]() to
avoid errors elsewhere.
https://forums.zotero.org/discussion/133523/synchronize-issue
Collections are now tracked as they're selected, added to, or dropped
on, and the five most recent usable targets are listed above the
full collection hierarchy by full path.
transformToDocument() needs a load group, which it takes from the source
document or from the window that created the XSLTProcessor. Neither of
those has existed since 0f2690eb75 in Zotero 8 stopped taking
XSLTProcessor from the hidden window, so the CSL 0.8 → 1.0 upgrade threw
NS_ERROR_FAILURE. In Word, this showed as "Zotero encountered an error
while updating your document."
https://forums.zotero.org/discussion/133543/
citeproc-rs is no longer maintained, and people who had enabled the
hidden pref were hitting errors.
This also drops the free() call on CSL engines, which only existed to
free the citeproc-rs wasm driver.
https://forums.zotero.org/discussion/133515/
If storing the API key failed, the pane kept showing the spinner and
"Waiting for login…" until the user clicked Cancel, even though the
login attempt was already over.
https://forums.zotero.org/discussion/133418/
Every failure shows "User canceled OS unlock entry" no matter what went
wrong. Test the store for the actual state, and give callers a message
describing what couldn't be accessed.
Both the keystore fallback prompt and the migration alert are reachable
from the credential read paths that a sync uses, so don't show if it's
an automatic sync.
Some Linux systems have no Secret Service running, and if users can't
change that (e.g., a managed system), storing an API key fails and login
never completes. Offer to store credentials unencrypted instead, and try
to encrypt them on a later read if the keystore becomes usable.
https://forums.zotero.org/discussion/133418/
Firefox 153 renders a menulist's popup as a native macOS menu, which
can't be opened to a submenu, so revealSelectedCondition() has done
nothing on macOS since the upgrade. Opt this popup out of native
rendering.
The conditions menu had its own find-as-you-type, which
Utilities.Internal.addMenuFindAsYouType() now provides for any menu.
Matching walks the menu rather than a cached list of every condition, so
typing can no longer select a condition the menu doesn't offer --
Collection and Saved Search are removed when the search spans multiple
libraries.
An attachment or annotation condition is shown with a short label inside
its submenu, so pass the full name to match on, which is what the
menulist shows once the condition is selected.
The Collection value menu was a flat list of every collection in the
library, with subcollections set apart by an indent (or hyphens before
606d8f19ba). Build it with Utilities.Internal.createMenuForTarget()
instead, using the new 'filter' feature to limit to collections. The new
FAYT helper preserves matching on subcollections.
If a subcollection is selected, open the path down to the subcollection
when opening the menu. (As of fx153, macOS renders popups as native
menus, which can't be opened to a submenu, so revert to non-native menus
there.) A collection in a submenu can't be a menulist's selected item,
so the condition holds the value and sets the menulist's label and icon
itself, with the collection's path as a tooltip.
A menulist's built-in find-as-you-type searches only the direct children
of its menupopup, so an item in a submenu can't be reached from the
keyboard. addMenuFindAsYouType() matches on every item in the menu
instead.
customElements.js opens a focused menulist when a space is pressed,
which would end a search partway through a name, so defer that while a
search is in progress.
The target menu isn't rebuilt between openings, so the checkmark stayed
on the target the menu was built with. In the New Collection dialog,
whose menu belongs to a menulist, that would leave two checkmarks if you
clicked a different collection and then reopened the menu.
On macOS, the current target in the New Collection dialog and the Add To
menus showed a checkmark in place of its folder icon -- type="checkbox"
makes nsMenuItemX::SetupIcon() skip the item. The `checked` attribute
alone marks it without suppressing the icon. Windows and Linux draw the
check in place of the icon either way.
Items are added to the collection created for an import as they're
saved, before the imported collection hierarchy exists, so an item only
in a subcollection ended up in the top collection as well as its own.
Remove those once the hierarchy has been created.
When everything imported belongs to a single top-level collection, that
collection is used for the import rather than being nested inside a
collection named after the file.
https://forums.zotero.org/discussion/133174/
Exporting a collection included only its subcollections, so an item
directly in the collection came through with no collection at all, and
an item in both the collection and a subcollection came through in only
the subcollection.
Exporting a selection of multiple collections exported a flat list of
items with no collections at all.
We now include the selected collection(s), with one exception: if a
saved search is also selected, we export a flat item list, since a
search can't be exported as a collection.
Forcing a Gatekeeper assessment seems to fix the extension when it's
broken. General theory: the system does an assessment while the app is
doing an in-place update, calculates a signature mismatch between the
parent app and the appex (or within one of the bundles?), and caches
that forever, so forcing a reassessment fixes it.
Mozilla's OSKeyStore.encrypt() encodes the string as UTF-8 before
encrypting, but its decrypt() returns the decrypted bytes as a binary
string without decoding them, so a WebDAV password containing non-ASCII
characters came back mojibake and authentication failed.
https://forums.zotero.org/discussion/133465/problem-login-into-webdav-server-with-10-0-1
addItems() passes its options to Zotero.Item::save(), but removeItems()
dropped everything but skipEditCheck, so callers couldn't batch the
resulting notifications.
Operators can be typed as the Advanced Search shows them, which every
locale already translates, and new keyword messages cover the join
words, "no"/"has", the units of a relative date, and the range forms.
Each range form is given as an example with its two ends filled in, so
that a locale can say it its own way and each form keeps its own words
(e.g., no "between 1970 to 2000").
"year is between 1970 and 2000", "year:1970-2000", "1970..2000", and
"1970 to 2000" all match values within the range, inclusive of both
ends. Ends can be a year, a month ("added between 2024-02 and
2024-06"), a day ("date:2020-03-01..2020-03-15"), or a count ("number
of tags between 2 and 5").
* Fix js-ctypes-based symlinking on Linux by using `libc.so.6` instead of `libc.so` in `OS.File.unixSymlink()` and `Zotero.File.createSymlink()`
* Use that instead of `/bin/ln`, which doesn't exist on NixOS
* Replace `/bin/ln` with `Zotero.File.createSymlink()` in symlinked-database test
---------
Co-authored-by: Dan Stillman <dstillman@zotero.org>
FSEvents is backed by a per-volume journal that only local volumes
have. On a network mount the stream is created and started
successfully but never delivers events, so the watcher would report
that nothing had changed for as long as it was used. Check the volume
with statfs() and fall back to scanning.
Since f21e1b2d32, a full local file scan no longer runs periodically and
on every manual sync, so locally missed attachments stayed marked for
upload and were skipped as unavailable instead of being downloaded.
"Reset File Sync History" marked every attachment for upload, including
files that had never been downloaded, so the forced download check added
in 404fc41b88 found nothing to download.
Missing files are now marked for download when the upload queue is
filled, and in at-sync-time mode they're downloaded in the same sync.
The reset marks them for download directly, and downloads are no longer
skipped just because there were no remote storage changes.
https://forums.zotero.org/discussion/133414/
getFilePath() and getFile() return a path whether or not the file
exists, so dragging an attachment that hadn't been downloaded handed
the drop target a path that didn't exist. Missing files also went
unreported by the drag data provider.
Firefox 140.14 in Zotero 10.0 made the drag transferable's data
principal null for chrome-initiated drags, so the file-promise stream
that File Explorer used couldn't be created and the drop failed with
"Unspecified error". On Windows the promise was just a file:// URL for
the attachment itself, so hand over the file directly instead, and
force a copy so that File Explorer doesn't move it out of storage.
https://forums.zotero.org/discussion/133399/https://bugzilla.mozilla.org/show_bug.cgi?id=2054665
If an update had already finished downloading when the download page was
shown, the page waited for an update-staged notification even when
staging wasn't possible -- e.g., a default Windows installation in
Program Files, which isn't writable -- so it never advanced past
"Applying update…". It now checks whether staging is actually in
progress.
Not yet tested in an updatable build
rollbackAllTransactions() called transactionInProgress() and
rollbackTransaction(), neither of which has existed since nested
transaction support was removed in 14d435b8d8, so it would have thrown
had either of its two callers still been reachable. Both are in code
long since replaced: Zotero.Sync.Server, which uses the synchronous
Zotero.DB.columnQuery(), and an error handler in Zotero.Sync.Storage
that nothing calls.
Drop it along with _transactionNestingLevel, _transactionRollback, and
_shutdown, which nothing reads.
Any error while saving a note prompted the user to restart Zotero, even
a transaction timeout caused by a long-running operation elsewhere.
Nothing has been written when the wait times out, so retry, unless newer
note content has been handed to the editor in the meantime.
https://forums.zotero.org/discussion/133298/
Editing a note flagged it stale, and the background drain indexed it and
then ran an FTS5 'optimize' -- a single statement that rewrites the
content index and can hold the shared database for over a minute --
because the queue was empty again. Note saves waiting on the connection
hit the transaction timeout and told the user to restart Zotero.
Merge the index in bounded steps instead, so no statement runs long
enough to keep other queries waiting, and only after enough items have
been indexed to be worth it.
https://forums.zotero.org/discussion/133298/
_getConnectionAsync() checked for an existing connection and then awaited
several filesystem operations before assigning one, so callers arriving in
that window each opened their own. Only the last was kept, and the rest
stayed open and unreachable, holding a mozStorage thread apiece until
shutdown.
A permanently closed connection kept its idle observer, so it went on
being notified and attempting backups for the life of the process. This
affects plugin databases, which are closed permanently when the plugin
shuts down.
The observer was added on every open with no matching removal, so each
reopen left behind another registration that received its own idle
notification. On macOS, where the periodic backup closes and reopens the
connection, the registrations accumulated and multiplied the work done
on each idle.
Addresses #6027