Add "Add Note from Annotations" menu option on items
Shows as a menu option when there's a single PDF attachment with annotations and as a submenu containing titles when there are multiple (even if there's only one attachment that actually has annotations) Also removes "Create Note from Annotations" on attachment items for now. (It might make sense to add that back, though "Add" would be a little weird for creating a sibling note, while using a different label would be confusing.)
This commit is contained in:
parent
3e37d31a49
commit
2c66133c7e
6 changed files with 114 additions and 25 deletions
|
@ -2302,7 +2302,7 @@ Zotero.Item.prototype.isEmbeddedImageAttachment = function() {
|
|||
* @return {Boolean} - Returns true if item is a stored or linked PDF attachment
|
||||
*/
|
||||
Zotero.Item.prototype.isPDFAttachment = function () {
|
||||
return this.isAttachment() && this.attachmentContentType == 'application/pdf';
|
||||
return this.isFileAttachment() && this.attachmentContentType == 'application/pdf';
|
||||
};
|
||||
|
||||
|
||||
|
@ -3769,6 +3769,34 @@ Zotero.Item.prototype.isImageAnnotation = function() {
|
|||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.numAnnotations = function (includeTrashed) {
|
||||
if (!this.isFileAttachment()) {
|
||||
throw new Error("numAnnotations() can only be called on file attachments");
|
||||
}
|
||||
|
||||
this._requireData('childItems');
|
||||
|
||||
if (!this._annotations) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var cacheKey = 'with' + (includeTrashed ? '' : 'out') + 'Trashed';
|
||||
|
||||
if (this._annotations[cacheKey]) {
|
||||
return this._annotations[cacheKey].length
|
||||
}
|
||||
|
||||
var rows = this._annotations.rows;
|
||||
// Remove trashed items if necessary
|
||||
if (!includeTrashed) {
|
||||
rows = rows.filter(row => !row.trashed);
|
||||
}
|
||||
var ids = rows.map(row => row.itemID);
|
||||
this._annotations[cacheKey] = ids;
|
||||
return rows.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns child annotations for an attachment item
|
||||
*
|
||||
|
@ -3776,8 +3804,8 @@ Zotero.Item.prototype.isImageAnnotation = function() {
|
|||
* @return {Zotero.Item[]}
|
||||
*/
|
||||
Zotero.Item.prototype.getAnnotations = function (includeTrashed) {
|
||||
if (!this.isAttachment()) {
|
||||
throw new Error("getAnnotations() can only be called on attachment items");
|
||||
if (!this.isFileAttachment()) {
|
||||
throw new Error("getAnnotations() can only be called on file attachments");
|
||||
}
|
||||
|
||||
this._requireData('childItems');
|
||||
|
@ -3792,7 +3820,7 @@ Zotero.Item.prototype.getAnnotations = function (includeTrashed) {
|
|||
return Zotero.Items.get([...this._annotations[cacheKey]]);
|
||||
}
|
||||
|
||||
var rows = this._annotations.rows.concat();
|
||||
var rows = this._annotations.rows;
|
||||
// Remove trashed items if necessary
|
||||
if (!includeTrashed) {
|
||||
rows = rows.filter(row => !row.trashed);
|
||||
|
|
|
@ -153,7 +153,7 @@ class EditorInstance {
|
|||
|
||||
async insertAnnotations(annotations) {
|
||||
await this._ensureNoteCreated();
|
||||
let html = await this._digestAnnotations(annotations);
|
||||
let html = await this._serializeAnnotations(annotations);
|
||||
if (html) {
|
||||
this._postMessage({ action: 'insertHTML', pos: -1, html });
|
||||
}
|
||||
|
@ -177,7 +177,12 @@ class EditorInstance {
|
|||
this._postMessage({ action: 'updateFont', font: this._getFont() });
|
||||
}
|
||||
|
||||
async _digestAnnotations(annotations) {
|
||||
|
||||
/**
|
||||
* @param {Zotero.Item[]} annotations
|
||||
* @return {String} - HTML string
|
||||
*/
|
||||
async _serializeAnnotations(annotations) {
|
||||
let html = '';
|
||||
for (let annotation of annotations) {
|
||||
let attachmentItem = await Zotero.Items.getAsync(annotation.attachmentItemID);
|
||||
|
@ -316,7 +321,7 @@ class EditorInstance {
|
|||
}
|
||||
else if (type === 'zotero/annotation') {
|
||||
let annotations = JSON.parse(data);
|
||||
html = await this._digestAnnotations(annotations);
|
||||
html = await this._serializeAnnotations(annotations);
|
||||
}
|
||||
if (html) {
|
||||
this._postMessage({ action: 'insertHTML', pos, html });
|
||||
|
@ -966,11 +971,11 @@ class EditorInstance {
|
|||
*
|
||||
* @param {Zotero.Item[]} annotations
|
||||
* @param {Integer} parentID Creates standalone note if not provided
|
||||
* @returns {Promise<Zotero.Item|undefined>}
|
||||
* @returns {Promise<Zotero.Item>}
|
||||
*/
|
||||
static async createNoteFromAnnotations(annotations, parentID) {
|
||||
if (!annotations.length) {
|
||||
return;
|
||||
throw new Error("No annotations provided");
|
||||
}
|
||||
let note = new Zotero.Item('note');
|
||||
note.libraryID = annotations[0].libraryID;
|
||||
|
@ -985,8 +990,8 @@ class EditorInstance {
|
|||
jsonAnnotation.attachmentItemID = attachmentItem.id;
|
||||
jsonAnnotations.push(jsonAnnotation);
|
||||
}
|
||||
let html = `<p>(${(new Date()).toLocaleString()})</p>\n`;
|
||||
html += await editorInstance._digestAnnotations(jsonAnnotations);
|
||||
let html = `<h1>${Zotero.getString('note.annotationsWithDate', new Date().toLocaleString())}</h1>\n`;
|
||||
html += await editorInstance._serializeAnnotations(jsonAnnotations);
|
||||
note.setNote(html);
|
||||
await note.saveTx();
|
||||
return note;
|
||||
|
|
|
@ -2735,6 +2735,8 @@ var ZoteroPane = new function()
|
|||
'showInLibrary',
|
||||
'sep1',
|
||||
'addNote',
|
||||
'createNoteFromAnnotations',
|
||||
'createNoteFromAnnotationsMenu',
|
||||
'addAttachments',
|
||||
'sep2',
|
||||
'findPDF',
|
||||
|
@ -2757,7 +2759,6 @@ var ZoteroPane = new function()
|
|||
'createParent',
|
||||
'renameAttachments',
|
||||
'reindexItem',
|
||||
'createNoteFromAnnotations'
|
||||
];
|
||||
|
||||
var m = {};
|
||||
|
@ -2922,6 +2923,33 @@ var ZoteroPane = new function()
|
|||
|
||||
if (item.isRegularItem() && !item.isFeedItem) {
|
||||
show.push(m.addNote, m.addAttachments, m.sep2);
|
||||
|
||||
// Create Note from Annotations
|
||||
let popup = document.getElementById('create-note-from-annotations-popup');
|
||||
popup.textContent = '';
|
||||
let eligibleAttachments = Zotero.Items.get(item.getAttachments())
|
||||
.filter(item => item.isPDFAttachment());
|
||||
let attachmentsWithAnnotations = eligibleAttachments.filter(x => x.numAnnotations());
|
||||
if (attachmentsWithAnnotations.length) {
|
||||
// Display submenu if there's more than one PDF attachment, even if
|
||||
// there's only attachment with annotations, so it's clear which one
|
||||
// the annotations are coming from
|
||||
if (eligibleAttachments.length > 1) {
|
||||
show.push(m.createNoteFromAnnotationsMenu);
|
||||
for (let attachment of attachmentsWithAnnotations) {
|
||||
let menuitem = document.createElement('menuitem');
|
||||
menuitem.setAttribute('label', attachment.getDisplayTitle());
|
||||
menuitem.onclick = () => {
|
||||
ZoteroPane.createNoteFromAnnotationsForAttachment(attachment);
|
||||
};
|
||||
popup.appendChild(menuitem);
|
||||
}
|
||||
}
|
||||
// Single attachment with annotations
|
||||
else {
|
||||
show.push(m.createNoteFromAnnotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Zotero.Attachments.canFindPDFForItem(item)) {
|
||||
|
@ -2973,11 +3001,6 @@ var ZoteroPane = new function()
|
|||
else if (!collectionTreeRow.isPublications()) {
|
||||
show.push(m.duplicateItem);
|
||||
}
|
||||
|
||||
|
||||
if (item.isPDFAttachment()) {
|
||||
show.push(m.createNoteFromAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
// Update attachment submenu
|
||||
|
@ -4680,14 +4703,37 @@ var ZoteroPane = new function()
|
|||
}
|
||||
};
|
||||
|
||||
this.createNoteFromSelected = function () {
|
||||
|
||||
this.createNoteFromAnnotationsForAttachment = async function (attachment) {
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
var note = await Zotero.EditorInstance.createNoteFromAnnotations(
|
||||
attachment.getAnnotations(), attachment.parentID
|
||||
);
|
||||
await this.selectItem(note.id);
|
||||
};
|
||||
|
||||
let item = this.getSelectedItems()[0];
|
||||
Zotero.EditorInstance.createNoteFromAnnotations(item.getAnnotations(), item.parentID);
|
||||
|
||||
this.createNoteFromAnnotationsFromSelected = async function () {
|
||||
if (!this.canEdit()) {
|
||||
this.displayCannotEditLibraryMessage();
|
||||
return;
|
||||
}
|
||||
var item = this.getSelectedItems()[0];
|
||||
var attachment;
|
||||
if (item.isRegularItem()) {
|
||||
attachment = Zotero.Items.get(item.getAttachments())
|
||||
.find(x => x.isPDFAttachment() && x.numAnnotations());
|
||||
}
|
||||
else if (item.isFileAttachment()) {
|
||||
attachment = item;
|
||||
}
|
||||
else {
|
||||
throw new Error("Not a regular item or file attachment");
|
||||
}
|
||||
return this.createNoteFromAnnotationsForAttachment(attachment);
|
||||
};
|
||||
|
||||
this.createEmptyParent = async function (item) {
|
||||
|
|
|
@ -280,6 +280,15 @@
|
|||
<menuseparator/>
|
||||
<!-- with icon: <menuitem class="menuitem-iconic" id="zotero-menuitem-note" label="&zotero.items.menu.attach.note;" oncommand="ZoteroPane_Local.newNote(false, this.parentNode.getAttribute('itemID'))"/>-->
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-attach-note" label="&zotero.items.menu.attach.note;" oncommand="ZoteroPane_Local.newNote(false, this.parentNode.getAttribute('itemKey'))"/>
|
||||
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-create-note-from-annotations"
|
||||
label="&zotero.items.menu.attach.noteFromAnnotations;"
|
||||
oncommand="ZoteroPane.createNoteFromAnnotationsFromSelected()"/>
|
||||
<menu class="menuitem-iconic zotero-menuitem-create-note-from-annotations"
|
||||
label="&zotero.items.menu.attach.noteFromAnnotations;">
|
||||
<menupopup id="create-note-from-annotations-popup"/>
|
||||
</menu>
|
||||
|
||||
<menu class="menu-iconic zotero-menuitem-attach" label="&zotero.items.menu.attach;">
|
||||
<menupopup id="zotero-add-attachment-popup">
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-attachments-web-link" label="&zotero.items.menu.attach.link.uri;" oncommand="var itemID = parseInt(this.parentNode.parentNode.parentNode.getAttribute('itemID')); ZoteroPane_Local.addAttachmentFromURI(true, itemID);"/>
|
||||
|
@ -308,7 +317,6 @@
|
|||
<menuitem class="menuitem-iconic zotero-menuitem-create-parent" oncommand="ZoteroPane_Local.createParentItemsFromSelected();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-rename-from-parent" oncommand="ZoteroPane_Local.renameSelectedAttachmentsFromParents()"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-reindex" oncommand="ZoteroPane_Local.reindexItem();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-create-note-from-annotations" label="&zotero.items.menu.createNoteFromAnnotations;" oncommand="ZoteroPane.createNoteFromSelected()"/>
|
||||
</menupopup>
|
||||
|
||||
<tooltip id="fake-tooltip"/>
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
|
||||
<!ENTITY zotero.items.menu.showInLibrary "Show in Library">
|
||||
<!ENTITY zotero.items.menu.attach.note "Add Note">
|
||||
<!ENTITY zotero.items.menu.attach.noteFromAnnotations "Add Note from Annotations">
|
||||
<!ENTITY zotero.items.menu.attach "Add Attachment">
|
||||
<!ENTITY zotero.items.menu.attach.link.uri "Attach Link to URI…">
|
||||
<!ENTITY zotero.items.menu.attach.file "Attach Stored Copy of File…">
|
||||
|
@ -101,7 +102,6 @@
|
|||
<!ENTITY zotero.items.menu.unrecognize "Undo Retrieve Metadata">
|
||||
<!ENTITY zotero.items.menu.reportMetadata "Report Incorrect Metadata">
|
||||
<!ENTITY zotero.items.menu.importAnnotations "Import Annotations">
|
||||
<!ENTITY zotero.items.menu.createNoteFromAnnotations "Create Note from Annotations">
|
||||
|
||||
<!ENTITY zotero.duplicatesMerge.versionSelect "Choose the version of the item to use as the master item:">
|
||||
<!ENTITY zotero.duplicatesMerge.fieldSelect "Select fields to keep from other versions of the item:">
|
||||
|
|
|
@ -620,6 +620,8 @@ findPDF.pdfWithMethod = PDF (%S)
|
|||
findPDF.noPDFsFound = No PDFs found
|
||||
findPDF.noPDFFound = No PDF found
|
||||
|
||||
note.annotationsWithDate = Annotations (%S)
|
||||
|
||||
attachment.fullText = Full Text
|
||||
attachment.acceptedVersion = Accepted Version
|
||||
attachment.submittedVersion = Submitted Version
|
||||
|
|
Loading…
Reference in a new issue