diff --git a/chrome/content/zotero/elements/itemBox.js b/chrome/content/zotero/elements/itemBox.js index 6526cb3224..3c95695763 100644 --- a/chrome/content/zotero/elements/itemBox.js +++ b/chrome/content/zotero/elements/itemBox.js @@ -2198,6 +2198,12 @@ this._focusNextField(1); } + focusField(fieldName) { + let field = this.shadowRoot.querySelector(`[fieldname="${fieldName}"][ztabindex]`); + if (!field) return false; + return this._focusNextField(field.getAttribute('ztabindex')); + } + /** * Advance the field focus forward or backward * diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index ed114ecee2..56142093be 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -1801,6 +1801,55 @@ var ZoteroPane = new function() }); + this.duplicateAndConvertSelectedItem = async function () { + if (this.getSelectedItems().length != 1 + || !['book', 'bookSection'].includes(this.getSelectedItems()[0].itemType)) { + throw new Error('duplicateAndConvertSelectedItem requires a single book or bookSection to be selected'); + } + + let authorCreatorType = Zotero.CreatorTypes.getID('author'); + let bookAuthorCreatorType = Zotero.CreatorTypes.getID('bookAuthor'); + + let original = this.getSelectedItems()[0]; + let duplicate = await this.duplicateSelectedItem(); + if (!duplicate) return null; + + if (duplicate.itemType == 'book') { + duplicate.setType(Zotero.ItemTypes.getID('bookSection')); + for (let i = 0; i < duplicate.numCreators(); i++) { + let creator = duplicate.getCreator(i); + if (creator.creatorTypeID == authorCreatorType) { + creator.creatorTypeID = bookAuthorCreatorType; + } + duplicate.setCreator(i, creator); + } + } + else { + duplicate.setField('title', false); // So bookTitle becomes title + duplicate.setType(Zotero.ItemTypes.getID('book')); + // Get creators from the original item because setType() will have changed the types + let creators = original.getCreators() + // Remove authors of the individual book section + .filter(creator => creator.creatorTypeID !== authorCreatorType); + for (let creator of creators) { + if (creator.creatorTypeID == bookAuthorCreatorType) { + creator.creatorTypeID = authorCreatorType; + } + } + duplicate.setCreators(creators); + } + + duplicate.addRelatedItem(original); + original.addRelatedItem(duplicate); + + await original.saveTx({ skipDateModifiedUpdate: true }); + await duplicate.saveTx(); + + document.getElementById('zotero-editpane-item-box').focusField('title'); + return duplicate; + }; + + /** * Return whether every selected item can be deleted from the current * collection context (library, trash, collection, etc.). @@ -3084,6 +3133,7 @@ var ZoteroPane = new function() 'toggleRead', 'addToCollection', 'removeItems', + 'duplicateAndConvert', 'duplicateItem', 'restoreToLibrary', 'moveToTrash', @@ -3363,6 +3413,12 @@ var ZoteroPane = new function() } } else if (!collectionTreeRow.isPublications()) { + if (item.itemType == 'book' || item.itemType == 'bookSection') { + menu.childNodes[m.duplicateAndConvert].setAttribute('label', Zotero.getString('pane.items.menu.duplicateAndConvert.' + + (item.itemType == 'book' ? 'toBookSection' : 'toBook'))); + show.add(m.duplicateAndConvert); + } + show.add(m.duplicateItem); } } diff --git a/chrome/content/zotero/zoteroPane.xhtml b/chrome/content/zotero/zoteroPane.xhtml index 3c548d798b..ea5dac541c 100644 --- a/chrome/content/zotero/zoteroPane.xhtml +++ b/chrome/content/zotero/zoteroPane.xhtml @@ -971,6 +971,7 @@ + diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 3cd74abddb..fd7993eb52 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -359,6 +359,8 @@ pane.items.menu.createParent = Create Parent Item… pane.items.menu.createParent.multiple = Create Parent Items pane.items.menu.renameAttachments = Rename File from Parent Metadata pane.items.menu.renameAttachments.multiple = Rename Files from Parent Metadata +pane.items.menu.duplicateAndConvert.toBookSection = Create Book Section +pane.items.menu.duplicateAndConvert.toBook = Create Book from Book Section pane.items.showItemInLibrary = Show Item in Library pane.items.letter.oneParticipant = Letter to %S