Add items to collection via context menu (#2360)

This commit is contained in:
Abe Jellinek 2022-02-21 16:36:37 -08:00 committed by GitHub
parent 90531ea2a4
commit f333585d98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 9 deletions

View file

@ -1693,16 +1693,19 @@ Zotero.Utilities.Internal = {
* Create a libraryOrCollection DOM tree to place in <menupopup> element.
* If has no children, returns a <menuitem> element, otherwise <menu>.
*
* @param {Library/Collection} libraryOrCollection
* @param {Node<menupopup>} elem parent element
* @param {function} clickAction function to execute on clicking the menuitem.
* @param {Library|Collection} libraryOrCollection
* @param {Node<menupopup>} elem Parent element
* @param {Zotero.Library|Zotero.Collection} currentTarget Currently selected item (displays as checked)
* @param {Function} clickAction function to execute on clicking the menuitem.
* Receives the event and libraryOrCollection for given item.
* @param {Function} disabledPred If provided, called on each library/collection
* to determine whether disabled
*
* @return {Node<menuitem>/Node<menu>} appended node
* @return {Node<menuitem>|Node<menu>} appended node
*/
createMenuForTarget: function(libraryOrCollection, elem, currentTarget, clickAction) {
createMenuForTarget: function(libraryOrCollection, elem, currentTarget, clickAction, disabledPred) {
var doc = elem.ownerDocument;
function _createMenuitem(label, value, icon, command) {
function _createMenuitem(label, value, icon, command, disabled) {
let menuitem = doc.createElement('menuitem');
menuitem.setAttribute("label", label);
menuitem.setAttribute("type", "checkbox");
@ -1711,6 +1714,7 @@ Zotero.Utilities.Internal = {
}
menuitem.setAttribute("value", value);
menuitem.setAttribute("image", icon);
menuitem.setAttribute("disabled", disabled);
menuitem.addEventListener('command', command);
menuitem.classList.add('menuitem-iconic');
return menuitem
@ -1722,7 +1726,11 @@ Zotero.Utilities.Internal = {
menu.setAttribute("value", value);
menu.setAttribute("image", icon);
// Allow click on menu itself to select a target
menu.addEventListener('click', command);
menu.addEventListener('click', (event) => {
if (event.target == menu) {
command(event);
}
});
menu.classList.add('menu-iconic');
let menupopup = doc.createElement('menupopup');
menu.appendChild(menupopup);
@ -1739,7 +1747,8 @@ Zotero.Utilities.Internal = {
imageSrc,
function (event) {
clickAction(event, libraryOrCollection);
}
},
disabledPred && disabledPred(libraryOrCollection)
);
var collections;
@ -1769,7 +1778,7 @@ Zotero.Utilities.Internal = {
menupopup.appendChild(doc.createElement('menuseparator'));
for (let collection of collections) {
let collectionMenu = this.createMenuForTarget(
collection, elem, currentTarget, clickAction
collection, elem, currentTarget, clickAction, disabledPred
);
menupopup.appendChild(collectionMenu);
}

View file

@ -2741,6 +2741,7 @@ var ZoteroPane = new function()
'sep3',
'toggleRead',
'duplicateItem',
'addToCollection',
'removeItems',
'restoreToLibrary',
'moveToTrash',
@ -3104,6 +3105,15 @@ var ZoteroPane = new function()
disable.add(m[i]);
}
}
// Add to collection
if (!collectionTreeRow.isFeed()
&& collectionTreeRow.editable
&& Zotero.Items.keepParents(items).every(item => item.isTopLevelItem())
) {
menu.childNodes[m.addToCollection].setAttribute('label', Zotero.getString('pane.items.menu.addToCollection'));
show.add(m.addToCollection);
}
// Remove from collection
if (collectionTreeRow.isCollection() && items.every(item => item.isTopLevelItem())) {
@ -3147,6 +3157,55 @@ var ZoteroPane = new function()
// add locate menu options
yield Zotero_LocateMenu.buildContextMenu(menu, true);
});
this.buildAddToCollectionMenu = function (event) {
if (event.target.id !== 'zotero-add-to-collection-popup') return;
let popup = document.getElementById('zotero-add-to-collection-popup');
let separator = document.getElementById('zotero-add-to-collection-separator');
while (popup.childElementCount > 2) {
popup.removeChild(popup.lastElementChild);
}
let items = Zotero.Items.keepParents(this.getSelectedItems());
let collections = Zotero.Collections.getByLibrary(this.getSelectedLibraryID());
for (let col of collections) {
let menuItem = Zotero.Utilities.Internal.createMenuForTarget(
col,
popup,
null,
(event, collection) => {
if (event.target.tagName == 'menuitem') {
this.addSelectedItemsToCollection(collection);
event.stopPropagation();
}
},
collection => items.every(item => collection.hasItem(item))
);
popup.append(menuItem);
}
separator.setAttribute('hidden', !collections.length);
};
this.addSelectedItemsToCollection = async function (collection, createNew = false) {
// Get items first because newCollection() will deselect
let items = Zotero.Items.keepParents(this.getSelectedItems());
if (createNew) {
if (collection) {
throw new Error('collection must be null if createNew is true');
}
let id = await this.newCollection();
collection = Zotero.Collections.get(id);
}
await Zotero.DB.executeTransaction(
() => collection.addItems(items.map(item => item.id)));
};
this.onItemTreeActivate = function(event, items) {
var viewOnDoubleClick = Zotero.Prefs.get('viewOnDoubleClick');

View file

@ -299,6 +299,12 @@
<menuseparator/>
<menuitem class="menuitem-iconic zotero-menuitem-toggle-read-item" oncommand="ZoteroPane_Local.toggleSelectedItemsRead();"/>
<menuitem class="menuitem-iconic zotero-menuitem-duplicate-item" label="&zotero.items.menu.duplicateItem;" oncommand="ZoteroPane_Local.duplicateSelectedItem().done();"/>
<menu class="menuitem-iconic zotero-menuitem-add-to-collection">
<menupopup id="zotero-add-to-collection-popup" onpopupshowing="ZoteroPane_Local.buildAddToCollectionMenu(event)">
<menuitem id="zotero-add-to-new-collection" label="&zotero.toolbar.newCollection.label;" oncommand="ZoteroPane_Local.addSelectedItemsToCollection(null, true)"/>
<menuseparator id="zotero-add-to-collection-separator"/>
</menupopup>
</menu>
<menuitem class="menuitem-iconic zotero-menuitem-remove-items" oncommand="ZoteroPane_Local.deleteSelectedItems();"/>
<menuitem class="menuitem-iconic zotero-menuitem-restore-to-library" label="&zotero.items.menu.restoreToLibrary;" oncommand="ZoteroPane_Local.restoreSelectedItems();"/>
<menuitem class="menuitem-iconic zotero-menuitem-move-to-trash" oncommand="ZoteroPane_Local.deleteSelectedItems(true, true);"/>

View file

@ -328,6 +328,7 @@ pane.items.menu.addNoteFromAnnotations = Add Note from Annotations
pane.items.menu.addNoteFromAnnotations.multiple = Add Notes from Annotations
pane.items.menu.findAvailablePDF = Find Available PDF
pane.items.menu.findAvailablePDF.multiple = Find Available PDFs
pane.items.menu.addToCollection = Add to Collection
pane.items.menu.remove = Remove Item from Collection…
pane.items.menu.remove.multiple = Remove Items from Collection…
pane.items.menu.removeFromPublications = Remove Item from My Publications…