mirror of
https://github.com/zotero/zotero.git
synced 2026-10-09 03:18:01 +00:00
citation dlg: sort libraries by cited count (#5925)
In list mode, sort libraries by the count of their items
cited in the current document, falling back to alphabetic sorting
when counts are equal, with "My Library" always getting
priority over other groups.
Fixes: #5924
(cherry picked from commit 8f44172342)
This commit is contained in:
parent
2a1779f5c1
commit
b5517e92c1
2 changed files with 81 additions and 3 deletions
|
|
@ -50,6 +50,9 @@ export class CitationDialogSearchHandler {
|
|||
this.selectedItems = null;
|
||||
this.openItems = null;
|
||||
this.citedItems = null;
|
||||
// number of cited items in each library, keyed by libraryID.
|
||||
// Populated once cited items are loaded in refreshCitedItems.
|
||||
this.citedItemCountsByLibrary = {};
|
||||
}
|
||||
|
||||
setSearchValue(str, enforceMinQueryLength) {
|
||||
|
|
@ -84,7 +87,8 @@ export class CitationDialogSearchHandler {
|
|||
// where key is selected/open/cited/{libraryID}, and group is the respective list of items.
|
||||
// Groups are sorted in the order they will be rendered:
|
||||
// Selected, Opened, Cited go first, followed by found library item groups ordered
|
||||
// by the number of results in each library.
|
||||
// by the number of cited items in each library (if loaded). Ties are broken by
|
||||
// keeping My Library first, then sorting other libraries alphabetically by name.
|
||||
// Items/notes in the libraries group are sorted via _createItemsSort/_createNotesSort comparators.
|
||||
// Takes citedItems as a parameter to filter them out from Selected, Opened and Cited groups.
|
||||
getOrderedSearchResultGroups(citedItemIDs = new Set()) {
|
||||
|
|
@ -128,8 +132,18 @@ export class CitationDialogSearchHandler {
|
|||
library.group.sort(itemComparator);
|
||||
});
|
||||
|
||||
// sort libraries by the number of items
|
||||
libraryItems.sort((a, b) => b.group.length - a.group.length);
|
||||
// sort libraries by the number of cited items in each library;
|
||||
// when counts are equal (or cited items have not been loaded yet),
|
||||
// keep My Library first and sort the rest alphabetically by name
|
||||
let collation = Zotero.getLocaleCollation();
|
||||
libraryItems.sort((a, b) => {
|
||||
let aCount = this.citedItemCountsByLibrary[a.key] || 0;
|
||||
let bCount = this.citedItemCountsByLibrary[b.key] || 0;
|
||||
if (aCount !== bCount) return bCount - aCount;
|
||||
if (a.key === Zotero.Libraries.userLibraryID) return -1;
|
||||
if (b.key === Zotero.Libraries.userLibraryID) return 1;
|
||||
return collation.compareString(1, Zotero.Libraries.get(a.key).name, Zotero.Libraries.get(b.key).name);
|
||||
});
|
||||
result.push(...libraryItems);
|
||||
|
||||
return result;
|
||||
|
|
@ -180,6 +194,13 @@ export class CitationDialogSearchHandler {
|
|||
async refreshCitedItems() {
|
||||
if (this.citedItems === null) {
|
||||
this.citedItems = await this._getCitedItems();
|
||||
// Record how many items from each library are already cited in the document.
|
||||
// Used for sorting to move currently cited libraries to the top of search results.
|
||||
for (let item of this.citedItems || []) {
|
||||
let libraryID = item.libraryID;
|
||||
if (!libraryID) continue;
|
||||
this.citedItemCountsByLibrary[libraryID] = (this.citedItemCountsByLibrary[libraryID] || 0) + 1;
|
||||
}
|
||||
}
|
||||
if (!this.citedItems) return;
|
||||
|
||||
|
|
|
|||
|
|
@ -571,6 +571,63 @@ describe("Citation Dialog", function () {
|
|||
assert.isOk(node);
|
||||
}
|
||||
});
|
||||
|
||||
it("should sort libraries in list mode by cited count, with user library first and others alphabetical on tie", async function () {
|
||||
let gammaGroup = await createGroup({ name: "gamma_group" });
|
||||
let betaGroup = await createGroup({ name: "beta_group" });
|
||||
let alphaGroup = await createGroup({ name: "alpha_group" });
|
||||
|
||||
// One search-matching item per library
|
||||
let userItem = await createDataObject('item', { title: "libsort_user" });
|
||||
let gammaItem = await createDataObject('item', { title: "libsort_gamma", libraryID: gammaGroup.libraryID });
|
||||
let betaItem = await createDataObject('item', { title: "libsort_beta", libraryID: betaGroup.libraryID });
|
||||
let alphaItem = await createDataObject('item', { title: "libsort_alpha", libraryID: alphaGroup.libraryID });
|
||||
// Cited item with a title that doesn't match the search query, so it
|
||||
// isn't removed from results.found by deduplication. Goes in gamma_group
|
||||
// so that group has a higher cited count than the rest.
|
||||
let citedItem = await createDataObject('item', { title: "cited_item", libraryID: gammaGroup.libraryID });
|
||||
|
||||
io.getItems = async () => [citedItem];
|
||||
io.isAllCitedDataLoaded = true;
|
||||
|
||||
await IOManager.toggleDialogMode("list");
|
||||
while (SearchHandler.searching) {
|
||||
await Zotero.Promise.delay(10);
|
||||
}
|
||||
|
||||
SearchHandler.selectedItems = [];
|
||||
SearchHandler.openItems = [];
|
||||
// Reset so refreshCitedItems re-fetches via io.getItems and
|
||||
// populates citedItemCountsByLibrary
|
||||
SearchHandler.citedItems = null;
|
||||
SearchHandler.citedItemCountsByLibrary = {};
|
||||
await SearchHandler.refreshCitedItems();
|
||||
|
||||
await dialog.currentLayout.search("libsort", { skipDebounce: true });
|
||||
|
||||
let libraryGroupKeys = SearchHandler.getOrderedSearchResultGroups()
|
||||
.filter(g => g.isLibrary)
|
||||
.map(g => g.key);
|
||||
|
||||
// Expected order:
|
||||
// 1. gamma_group -- only library with a cited item (cited count wins)
|
||||
// 2. user library -- userLibraryID wins ties over other libraries
|
||||
// 3. alpha_group -- alphabetical fallback among remaining libraries
|
||||
// 4. beta_group
|
||||
assert.deepEqual(libraryGroupKeys, [
|
||||
gammaGroup.libraryID,
|
||||
userItem.libraryID,
|
||||
alphaGroup.libraryID,
|
||||
betaGroup.libraryID
|
||||
]);
|
||||
|
||||
// Reset cited state so subsequent tests aren't affected
|
||||
SearchHandler.citedItems = [];
|
||||
SearchHandler.citedItemCountsByLibrary = {};
|
||||
|
||||
io.getItems = () => [];
|
||||
delete io.isAllCitedDataLoaded;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Dialog loading", function () {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue