diff --git a/chrome/content/zotero/collectionTree.jsx b/chrome/content/zotero/collectionTree.jsx
index de84ca5269..16d2cd1122 100644
--- a/chrome/content/zotero/collectionTree.jsx
+++ b/chrome/content/zotero/collectionTree.jsx
@@ -1540,7 +1540,8 @@ var CollectionTree = class CollectionTree extends LibraryTree {
tags: Zotero.Prefs.get('groups.copyTags'),
childNotes: Zotero.Prefs.get('groups.copyChildNotes'),
childLinks: Zotero.Prefs.get('groups.copyChildLinks'),
- childFileAttachments: Zotero.Prefs.get('groups.copyChildFileAttachments')
+ childFileAttachments: Zotero.Prefs.get('groups.copyChildFileAttachments'),
+ annotations: Zotero.Prefs.get('groups.copyAnnotations'),
};
var copyItem = async function (item, targetLibraryID, options) {
var targetLibraryType = Zotero.Libraries.get(targetLibraryID).libraryType;
@@ -1612,7 +1613,12 @@ var CollectionTree = class CollectionTree extends LibraryTree {
return false;
}
- return Zotero.Attachments.copyAttachmentToLibrary(item, targetLibraryID);
+ let newAttachment = Zotero.Attachments.copyAttachmentToLibrary(item, targetLibraryID);
+ if (options.annotations) {
+ await Zotero.Items.copyChildItems(item, newAttachment);
+ }
+
+ return newAttachment.id;
}
// Create new clone item in target library
@@ -1675,7 +1681,13 @@ var CollectionTree = class CollectionTree extends LibraryTree {
continue;
}
}
- await Zotero.Attachments.copyAttachmentToLibrary(attachment, targetLibraryID, newItemID);
+ let newAttachment = await Zotero.Attachments.copyAttachmentToLibrary(
+ attachment, targetLibraryID, newItemID
+ );
+
+ if (options.annotations) {
+ await Zotero.Items.copyChildItems(attachment, newAttachment);
+ }
}
}
@@ -1804,6 +1816,7 @@ var CollectionTree = class CollectionTree extends LibraryTree {
copyOptions.childNotes = io.includeNotes;
copyOptions.childFileAttachments = io.includeFiles;
copyOptions.childLinks = true;
+ copyOptions.annotations = false;
['keepRights', 'license', 'licenseName'].forEach(function (field) {
copyOptions[field] = io[field];
});
diff --git a/chrome/content/zotero/preferences/preferences_general.xul b/chrome/content/zotero/preferences/preferences_general.xul
index 4e5c402420..289aaf2fab 100644
--- a/chrome/content/zotero/preferences/preferences_general.xul
+++ b/chrome/content/zotero/preferences/preferences_general.xul
@@ -42,6 +42,7 @@
+
@@ -96,6 +97,7 @@
+
diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js
index 433cfc11e2..196cef2b69 100644
--- a/chrome/content/zotero/xpcom/attachments.js
+++ b/chrome/content/zotero/xpcom/attachments.js
@@ -2682,6 +2682,8 @@ Zotero.Attachments = new function(){
/**
* Copy attachment item, including file, to another library
+ *
+ * @return {Zotero.Item} - The new attachment
*/
this.copyAttachmentToLibrary = Zotero.Promise.coroutine(function* (attachment, libraryID, parentItemID) {
if (attachment.libraryID == libraryID) {
@@ -2708,7 +2710,7 @@ Zotero.Attachments = new function(){
}
yield newAttachment.addLinkedItem(attachment);
- return newAttachment.id;
+ return newAttachment;
});
diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js
index 85906cd5fb..3dc94a5b33 100644
--- a/chrome/content/zotero/xpcom/data/items.js
+++ b/chrome/content/zotero/xpcom/data/items.js
@@ -882,6 +882,36 @@ Zotero.Items = function() {
});
+ /**
+ * Copy child items from one item to another (e.g., in another library)
+ *
+ * Requires a transaction
+ */
+ this.copyChildItems = async function (fromItem, toItem) {
+ Zotero.DB.requireTransaction();
+
+ var fromGroup = fromItem.library.isGroup;
+
+ // Annotations on files
+ if (fromItem.isFileAttachment()) {
+ let annotations = fromItem.getAnnotations();
+ for (let annotation of annotations) {
+ let newAnnotation = annotation.clone(toItem.libraryID);
+ newAnnotation.parentItemID = toItem.id;
+ // If there's no explicit author and we're copying from a group, set the author
+ // to the creating user
+ if (!annotation.annotationAuthorName && fromGroup) {
+ newAnnotation.annotationAuthorName =
+ Zotero.Users.getName(annotation.createdByUserID);
+ }
+ await newAnnotation.save();
+ }
+ }
+
+ // TODO: Other things as necessary
+ };
+
+
/**
* Move child items from one item to another
*
diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd
index 540f8297d7..fb20dd2fa7 100644
--- a/chrome/locale/en-US/zotero/preferences.dtd
+++ b/chrome/locale/en-US/zotero/preferences.dtd
@@ -30,6 +30,7 @@
+
diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js
index 8e011d74e5..832db2deb6 100644
--- a/defaults/preferences/zotero.js
+++ b/defaults/preferences/zotero.js
@@ -51,6 +51,7 @@ pref("extensions.zotero.reopenPanesOnRestart", true);
pref("extensions.zotero.groups.copyChildLinks", true);
pref("extensions.zotero.groups.copyChildFileAttachments", true);
+pref("extensions.zotero.groups.copyAnnotations", true);
pref("extensions.zotero.groups.copyChildNotes", true);
pref("extensions.zotero.groups.copyTags", true);
diff --git a/test/tests/collectionTreeTest.js b/test/tests/collectionTreeTest.js
index 717db9ea17..8d095813bd 100644
--- a/test/tests/collectionTreeTest.js
+++ b/test/tests/collectionTreeTest.js
@@ -814,21 +814,22 @@ describe("Zotero.CollectionTree", function() {
});
});
- it("should copy an item with an attachment to a group", function* () {
- var group = yield createGroup();
+ it("should copy an item with a PDF attachment containing annotations to a group", async function () {
+ var group = await createGroup();
- var item = yield createDataObject('item', false, { skipSelect: true });
+ var item = await createDataObject('item', false, { skipSelect: true });
var file = getTestDataDirectory();
- file.append('test.png');
- var attachment = yield Zotero.Attachments.importFromFile({
- file: file,
+ file.append('test.pdf');
+ var attachment = await Zotero.Attachments.importFromFile({
+ file,
parentItemID: item.id
});
+ var annotation = await createAnnotation('highlight', attachment);
- var ids = (yield onDrop('item', 'L' + group.libraryID, [item.id])).ids;
+ var ids = (await onDrop('item', 'L' + group.libraryID, [item.id])).ids;
- yield cv.selectLibrary(group.libraryID);
- yield waitForItemsLoad(win);
+ await cv.selectLibrary(group.libraryID);
+ await waitForItemsLoad(win);
// Check parent
var itemsView = win.ZoteroPane.itemsView;
@@ -837,7 +838,7 @@ describe("Zotero.CollectionTree", function() {
assert.equal(treeRow.ref.libraryID, group.libraryID);
assert.equal(treeRow.ref.id, ids[0]);
// New item should link back to original
- var linked = yield item.getLinkedItem(group.libraryID);
+ var linked = await item.getLinkedItem(group.libraryID);
assert.equal(linked.id, treeRow.ref.id);
// Check attachment
@@ -847,11 +848,44 @@ describe("Zotero.CollectionTree", function() {
treeRow = itemsView.getRow(1);
assert.equal(treeRow.ref.id, ids[1]);
// New attachment should link back to original
- linked = yield attachment.getLinkedItem(group.libraryID);
+ linked = await attachment.getLinkedItem(group.libraryID);
assert.equal(linked.id, treeRow.ref.id);
+ // Check annotation
+ var groupAttachment = Zotero.Items.get(treeRow.ref.id);
+ var annotations = groupAttachment.getAnnotations();
+ assert.lengthOf(annotations, 1);
+
return group.eraseTx();
- })
+ });
+
+ it("should copy a group item with a PDF attachment containing annotations to the personal library", async function () {
+ var group = await createGroup();
+ await cv.selectLibrary(group.libraryID);
+
+ var groupItem = await createDataObject('item', { libraryID: group.libraryID });
+ var file = getTestDataDirectory();
+ file.append('test.pdf');
+ var attachment = await Zotero.Attachments.importFromFile({
+ file,
+ parentItemID: groupItem.id
+ });
+ var annotation = await createAnnotation('highlight', attachment);
+ await Zotero.Users.setName(12345, 'Name');
+ annotation.createdByUserID = 12345;
+
+ var ids = (await onDrop('item', 'L1', [groupItem.id])).ids;
+ var newItem = Zotero.Items.get(ids[0]);
+
+ var newAttachment = Zotero.Items.get(newItem.getAttachments())[0];
+
+ // Check annotation
+ var annotations = newAttachment.getAnnotations();
+ assert.lengthOf(annotations, 1);
+ assert.equal(annotations[0].annotationAuthorName, 'Name');
+
+ return group.eraseTx();
+ });
it("should not copy an item or its attachment to a group twice", function* () {
var group = yield getGroup();