Remove the isLinked item-list column and introduce an Unlinked Items
container row, with a localized label in zotero.properties.
Grouped mode now activates when unlinked items are present, and selection/
activation logic explicitly targets item rows while allowing container-row
navigation.
Replace Proxy-wrapped items and hacky rendering overrides
with proper ItemTreeRow subclasses and a custom
ItemTreeRowProvider.
- LibraryItemTreeRow: expandable container for library
grouping with sortChildren opt-in
- CitationExplorerItemTreeRow: row with citation metadata,
explicit id for CSL-only items, isContainer/
isContainerEmpty overrides to suppress twisties
- CitationExplorerRowProvider: groups items by library,
delegates sorting to base class via _sort()/_compareRows()
- CitationExplorerItemTree: custom tree with row provider
- Enable all standard columns (hidden by default) with
column picker and persistence
- isLinked column excluded from picker via
showInColumnPicker: false
- Remove persistColumns from citationDialog (consolidated
into columnPicker in prior commit)
- Add .library-container-row styling
If the keystore's secret is replaced -- say, after a keyring reset --
the stored value won't be able to be decrypted again, so tell them to
try logging in again instead of trying to fix their keyring.
https://forums.zotero.org/discussion/133603/
unload() closes and re-adds the tab, and the close recorded an undo-close
history entry, so Undo Close Tab could open a duplicate of a tab that was
still open.
_addEntry() wrote the row with REPLACE INTO, listing only itemID and
data, so flag reverted to its default of 0. It's called for every match
on every update, not just new ones, so a retraction the user had hidden
came back as soon as the list changed and Zotero restarted.
A window is marked as closed before its unload handlers run, so the tab
events fired from ZoteroPane.destroy() warned about every observer that
the closing window hadn't torn down yet. The leak check now also requires
the window to be detached from its docShell, and it covers functions. It
caught an observer that outlived its window -- the sync-reminder API key
observer, which is now unregistered on teardown.
Listeners added to the item and collection trees' event bindings
survived unregister() and held ZoteroPane and the views for as long
as the tree objects did. makeClassEventDispatcher() now provides
clearEventListeners(), which the trees call on unregister, so callers
don't need to remove their own listeners. The collection tree focus
listener, a plain DOM listener, is removed in destroy().
Hiding the tag selector destroyed the TagSelectorContainer but left
its media-query listener registered, keeping the destroyed instance
alive for the lifetime of the window and firing setState() on the
unmounted component when the display density changed. The fontSize
pref observer id was also overwritten by the uiDensity registration,
so it was never unregistered.
Selecting a collection doesn't wait for the tag selector to re-render,
so waitForTagSelector() could be resolved by the initial render instead
of the awaited change, and the assertions could run against a stale tag
list.
The cached retractions list is saved with the current data version from
the code, which we can bump to make clients discard their cached data
and refetch it. We've never actually done that, but if we did, it
would've hit a bug: init() would've started the refetch but still sent
the cached ETag, so if the list itself hadn't changed, the server
would've returned 304 and nothing would have been updated. The stale
version then would have survived, so the refetch would have been retried
on every startup.
Retraction Watch has renamed, merged, and added reason terms since these
were added, leaving only 65 of the 102 entries matching a term still in
use. 90% of retracted items had at least one reason that didn't show a
description, and 21% showed none at all. Rebuilt from the current
Appendix B list, which covers every reason in the data.