mirror of
https://github.com/zotero/zotero.git
synced 2026-08-28 05:25:31 +00:00
Update items-in-view count when rows change without a selection
Notifier events that added or removed rows (e.g., items downloaded during a sync) didn't update the no-selection message in the item pane, so the count went stale until the selection changed. The row provider now emits a rowCountChange event, and the pane re-renders the count, debounced, when nothing is selected.
This commit is contained in:
parent
b8cbdc8c95
commit
fe35127f50
3 changed files with 73 additions and 1 deletions
|
|
@ -732,6 +732,7 @@ class CollectionViewItemTreeRowProvider extends ItemTreeRowProvider {
|
|||
this._removeRows(rows);
|
||||
rowsToInvalidate = true; // all rows
|
||||
this.runListeners('update', true);
|
||||
this.itemTree.runListeners('rowCountChange');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1084,6 +1085,10 @@ class CollectionViewItemTreeRowProvider extends ItemTreeRowProvider {
|
|||
selection: rowsToSelect
|
||||
});
|
||||
}
|
||||
|
||||
if (madeChanges || refresh) {
|
||||
this.itemTree.runListeners('rowCountChange');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1102,8 +1107,10 @@ class CollectionViewItemTree extends ItemTree {
|
|||
// Triggered when the item tree is refreshed:
|
||||
// - Collection/view changed (changeCollectionTreeRow)
|
||||
// - Search/filter updated (setFilter)
|
||||
// - Items added/removed/modified (notify -> refresh)
|
||||
this.onRefresh = this.createEventBinding('refresh');
|
||||
// Triggered when notifier events change the rows in the view without a full refresh
|
||||
// (e.g., items added during a sync)
|
||||
this.onRowCountChange = this.createEventBinding('rowCountChange');
|
||||
}
|
||||
|
||||
get viewMode() { return this.rowProvider.viewMode; }
|
||||
|
|
|
|||
|
|
@ -1613,6 +1613,20 @@ var ZoteroPane = new function () {
|
|||
ZoteroPane.itemsView.onRefresh.addListener(async () => {
|
||||
await ZoteroPane.itemSelected();
|
||||
});
|
||||
// Also update the count when rows are added or removed by notifier events with
|
||||
// nothing selected (e.g., items downloaded during a sync). Debounced so that the
|
||||
// item pane doesn't re-render within the notifier dispatch or once per event in
|
||||
// a burst of changes.
|
||||
let updateUnselectedCount = Zotero.Utilities.debounce(() => {
|
||||
if (!ZoteroPane.itemsView.selection.count) {
|
||||
ZoteroPane.itemSelected();
|
||||
}
|
||||
}, 100);
|
||||
ZoteroPane.itemsView.onRowCountChange.addListener(() => {
|
||||
if (!ZoteroPane.itemsView.selection.count) {
|
||||
updateUnselectedCount();
|
||||
}
|
||||
});
|
||||
ZoteroPane.itemsView.waitForLoad().then(() => Zotero.uiIsReady());
|
||||
|
||||
ItemTreeMenuBar.setItemTreeSortKeys(ZoteroPane.itemsView);
|
||||
|
|
|
|||
|
|
@ -250,6 +250,57 @@ describe("Item pane", function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe("Message pane", function () {
|
||||
it("should update items-in-view count when an item is added with no selection", async function () {
|
||||
var collection = await createDataObject('collection');
|
||||
await ZoteroPane.collectionsView.selectCollection(collection.id);
|
||||
await waitForItemsLoad(win);
|
||||
|
||||
var messageBox = doc.querySelector('#zotero-item-pane-message-box');
|
||||
var emptyMessage = await doc.l10n.formatValue('item-pane-message-unselected', { count: 0 });
|
||||
var oneItemMessage = await doc.l10n.formatValue('item-pane-message-unselected', { count: 1 });
|
||||
for (let i = 0; i < 100 && !messageBox.textContent.includes(emptyMessage); i++) {
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
assert.include(messageBox.textContent, emptyMessage);
|
||||
|
||||
await createDataObject('item', { collections: [collection.id] }, { skipSelect: true });
|
||||
|
||||
for (let i = 0; i < 100 && !messageBox.textContent.includes(oneItemMessage); i++) {
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
assert.include(messageBox.textContent, oneItemMessage);
|
||||
});
|
||||
|
||||
it("should update items-in-view count when a restored item is removed from the trash with no selection", async function () {
|
||||
var group = await createGroup();
|
||||
var item = await createDataObject('item', { libraryID: group.libraryID, deleted: true }, { skipSelect: true });
|
||||
await selectTrash(win, group.libraryID);
|
||||
|
||||
var messageBox = doc.querySelector('#zotero-item-pane-message-box');
|
||||
var emptyMessage = await doc.l10n.formatValue('item-pane-message-unselected', { count: 0 });
|
||||
var oneItemMessage = await doc.l10n.formatValue('item-pane-message-unselected', { count: 1 });
|
||||
for (let i = 0; i < 100 && !messageBox.textContent.includes(oneItemMessage); i++) {
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
assert.include(messageBox.textContent, oneItemMessage);
|
||||
|
||||
// Restore the item without notifications, so that the row remains until a
|
||||
// 'refresh' notification arrives (e.g., from retractions or full-text
|
||||
// indexing) and the tree notices that the item is no longer deleted
|
||||
item.deleted = false;
|
||||
await item.saveTx({ skipNotifier: true });
|
||||
assert.include(messageBox.textContent, oneItemMessage);
|
||||
|
||||
await Zotero.Notifier.trigger('refresh', 'item', [item.id]);
|
||||
|
||||
for (let i = 0; i < 100 && !messageBox.textContent.includes(emptyMessage); i++) {
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
assert.include(messageBox.textContent, emptyMessage);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Info pane", function () {
|
||||
before(async () => {
|
||||
await activateZoteroPane();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue