getAllDescendents -> getDescendantItems refactor

getDescendantItems takes an optional argument to
return annotations and is now called in other instances
where we had to find and return items' descendants
This commit is contained in:
Bogdan Abaev 2026-08-17 14:47:39 -07:00
parent 2cee565379
commit 2cf29e5cc4
6 changed files with 25 additions and 48 deletions

View file

@ -721,7 +721,7 @@ class CollectionViewItemTreeRowProvider extends ItemTreeRowProvider {
if (!item) continue;
let topLevelItem = item.topLevelItem;
let isAnythingDeleted = topLevelItem.deleted
|| topLevelItem.getAllDescendents(true).length > topLevelItem.getAllDescendents(false).length;
|| topLevelItem.getDescendantItems({ includeTrashed: true }).length > topLevelItem.getDescendantItems().length;
// Remove the top-level item's row if neither it nor any of its
// descendents remain trashed
if (!isAnythingDeleted) {

View file

@ -260,12 +260,7 @@ export class CitationDialogSearchHandler {
isItemWithAnnotations(item) {
if (item.isAnnotation()) return true;
if (item.isFileAttachment() && item.getAnnotations().length) return true;
if (item.isRegularItem()) {
let attachments = Zotero.Items.get(item.getAttachments());
return attachments.some(att => att.isFileAttachment() && att.getAnnotations().length);
}
return false;
return item.getDescendantItems().some(descendent => descendent.isAnnotation());
}
isItemWithNotes(item) {
@ -279,10 +274,7 @@ export class CitationDialogSearchHandler {
getAllAnnotations(item) {
if (item.isAnnotation()) return [item];
if (item.isFileAttachment()) return item.getAnnotations();
let attachmentIDs = item.getAttachments();
let attachments = Zotero.Items.get(attachmentIDs).filter(item => item.isFileAttachment());
let annotations = attachments.flatMap(attachment => attachment.getAnnotations());
let annotations = item.getDescendantItems().filter(descendent => descendent.isAnnotation());
annotations.sort((a, b) => {
if (a.parentItemID !== b.parentItemID) return 0;
return (a.annotationSortIndex > b.annotationSortIndex) - (a.annotationSortIndex < b.annotationSortIndex);

View file

@ -741,6 +741,7 @@ Zotero.DataObjectUtilities = {
isRegularItem: () => false, // Should be false to prevent items dropped into deleted searches
getNotes: () => [],
getAttachments: () => [],
getDescendantItems: () => [],
isFileAttachment: () => false,
isTopLevelItem: () => false,
getField: function (field, _) {

View file

@ -2460,28 +2460,30 @@ Zotero.Item.prototype.numChildren = function (includeTrashed) {
/**
* Get all descendents of an item -- child notes and attachments of a regular item,
* annotations of its file attachments, and annotations of a standalone file attachment
* Get descendant items -- child notes and attachments of a regular item, plus
* annotations of its file attachments; annotations of a standalone file attachment
*
* @param {Boolean} includeTrashed Include trashed items
* @return {Zotero.Item[]}
* @param {Object} [options]
* @param {Boolean} [options.includeTrashed=false] Include trashed items
* @param {Boolean} [options.includeAnnotations=true] Include annotations of file attachments
* @return {Zotero.Item[]}
*/
Zotero.Item.prototype.getAllDescendents = function (includeTrashed) {
let attachments = [];
let notes = [];
let annotations = [];
Zotero.Item.prototype.getDescendantItems = function ({ includeTrashed = false, includeAnnotations = true } = {}) {
let descendents = [];
if (this.isRegularItem()) {
attachments = Zotero.Items.get(this.getAttachments(includeTrashed));
notes = Zotero.Items.get(this.getNotes(includeTrashed));
for (let attachment of attachments) {
if (!attachment.isFileAttachment()) continue;
annotations.push(...attachment.getAnnotations(includeTrashed));
let attachments = Zotero.Items.get(this.getAttachments(includeTrashed));
descendents.push(...attachments, ...Zotero.Items.get(this.getNotes(includeTrashed)));
if (includeAnnotations) {
for (let attachment of attachments) {
if (!attachment.isFileAttachment()) continue;
descendents.push(...attachment.getAnnotations(includeTrashed));
}
}
}
else if (this.isFileAttachment()) {
annotations = this.getAnnotations(includeTrashed);
else if (includeAnnotations && this.isFileAttachment()) {
descendents.push(...this.getAnnotations(includeTrashed));
}
return [...attachments, ...notes, ...annotations];
return descendents;
};

View file

@ -1336,7 +1336,7 @@ Zotero.Items = function () {
// Remove all child items too
if (item.isRegularItem()) {
allItems.push(...this.get(item.getNotes(true).concat(item.getAttachments(true))));
allItems.push(...item.getDescendantItems({ includeTrashed: true, includeAnnotations: false }));
}
allItems.push(item);

View file

@ -2859,7 +2859,7 @@ var ZoteroPane = new function () {
}
let parent = this.itemsView.getRow(row).ref;
let childIDs = [];
let childItems = [];
let subcollections = [];
if (parent instanceof Zotero.Collection) {
// If the restored item is a collection, restore its subcollections too
@ -2868,26 +2868,8 @@ var ZoteroPane = new function () {
}
}
else {
if (!parent.isNote()) {
childIDs.push(...parent.getNotes(true));
}
// Include annotations of the item's file attachments, or of the item
// itself for a standalone file attachment
let fileAttachments = [];
if (parent.isRegularItem()) {
let attachmentIDs = parent.getAttachments(true);
childIDs.push(...attachmentIDs);
fileAttachments = Zotero.Items.get(attachmentIDs)
.filter(attachment => attachment.isFileAttachment());
}
else if (parent.isFileAttachment()) {
fileAttachments = [parent];
}
for (let attachment of fileAttachments) {
childIDs.push(...attachment.getAnnotations(true).map(a => a.id));
}
childItems = parent.getDescendantItems({ includeTrashed: true });
}
let childItems = Zotero.Items.get(childIDs);
if (isSelected(parent)) {
if (parent.deleted) {
parent.deleted = false;