Allow dragging items, collections, and searches into trash (#5033)

Fixes: #1943
This commit is contained in:
abaevbog 2025-02-12 23:58:25 -08:00 • committed by GitHub
parent 5978353d57
commit 506f3b14e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 3 deletions

View file

@ -1426,11 +1426,12 @@ var CollectionTree = class CollectionTree extends LibraryTree {
event.dataTransfer.effectAllowed = 'copyMove';
}
if (!treeRow.isCollection()) {
if (!treeRow.isCollection() && !treeRow.isSearch()) {
return;
}
event.dataTransfer.setData("zotero/collection", treeRow.ref.id);
Zotero.debug("Dragging collection " + treeRow.id);
let type = treeRow.isCollection() ? "zotero/collection" : "zotero/search";
event.dataTransfer.setData(type, treeRow.ref.id);
Zotero.debug(`Dragging ${type} ` + treeRow.id);
}
onDragOver(event, index) {
@ -1567,6 +1568,21 @@ var CollectionTree = class CollectionTree extends LibraryTree {
// Directly on a row
if (orient === 0) {
if (!treeRow.editable) {
// Can drop collections, searches, and items into trash of their own library
if (treeRow.isTrash()) {
let objects = [];
if (dataType === 'zotero/item') {
objects = Zotero.Items.get(data);
}
else if (dataType === 'zotero/collection') {
objects = Zotero.Collections.get(data);
}
else if (dataType === 'zotero/search') {
objects = Zotero.Searches.get(data);
}
let allInSameLibrary = objects.every(object => object.libraryID === treeRow.ref.libraryID);
return allInSameLibrary;
}
// Zotero.debug("Drop target not editable");
return false;
}
@ -2096,6 +2112,27 @@ var CollectionTree = class CollectionTree extends LibraryTree {
childFileAttachments: Zotero.Prefs.get('groups.copyChildFileAttachments'),
annotations: Zotero.Prefs.get('groups.copyAnnotations'),
};
// Dropping items, collections, or searches into trash
if (targetTreeRow.isTrash()) {
let objects = [];
if (dataType == 'zotero/collection') {
objects = await Zotero.Collections.getAsync(data);
}
else if (dataType == 'zotero/search') {
objects = await Zotero.Searches.getAsync(data);
}
else if (dataType == 'zotero/item') {
objects = await Zotero.Items.getAsync(data);
}
await Zotero.DB.executeTransaction(async function () {
for (let obj of objects) {
obj.deleted = true;
await obj.save();
}
});
return;
}
var targetLibraryID = targetTreeRow.ref.libraryID;
var targetCollectionID = targetTreeRow.isCollection() ? targetTreeRow.ref.id : false;

View file

@ -2082,6 +2082,11 @@ Zotero.DragDrop = {
let ids = dt.getData('zotero/item').split(",").map(id => parseInt(id));
dragData.data = ids;
}
else if (dt.types.includes('zotero/search')) {
dragData.dataType = 'zotero/search';
let ids = dt.getData('zotero/search').split(",").map(id => parseInt(id));
dragData.data = ids;
}
else {
if (dt.types.includes('application/x-moz-file')) {
dragData.dataType = 'application/x-moz-file';

View file

@ -1118,6 +1118,14 @@ describe("Zotero.CollectionTree", function() {
assert.isTrue(droppedItem.deleted);
})
it("can delete an item by dropping it into the trash", async function () {
var item = await createDataObject('item', false, { skipSelect: true });
var deferred = Zotero.Promise.defer();
deferred.resolve();
await onDrop('item', 'T' + userLibraryID, [item.id], deferred.promise);
assert.isTrue(item.deleted);
});
})
@ -1373,6 +1381,14 @@ describe("Zotero.CollectionTree", function() {
await group1.eraseTx();
await group2.eraseTx();
});
it("can delete a collection by dropping it into the trash", async function () {
var collection = await createDataObject('collection');
var deferred = Zotero.Promise.defer();
deferred.resolve();
await onDrop('collection', 'T' + userLibraryID, [collection.id], deferred.promise);
assert.isTrue(collection.deleted);
})
})
@ -1430,6 +1446,16 @@ describe("Zotero.CollectionTree", function() {
assert.equal(treeRow.ref.id, item.id);
})
})
describe("with searches", function () {
it("can delete a saved search by dropping it into the trash", async function () {
var search = await createDataObject('search');
var deferred = Zotero.Promise.defer();
deferred.resolve();
await onDrop('search', 'T' + userLibraryID, [search.id], deferred.promise);
assert.isTrue(search.deleted);
})
});
})
describe("Feeds pseudo-library", function () {