diff --git a/chrome/content/zotero/preferences/preferences_general.xul b/chrome/content/zotero/preferences/preferences_general.xul
index fc0c087e8f..c908652c30 100644
--- a/chrome/content/zotero/preferences/preferences_general.xul
+++ b/chrome/content/zotero/preferences/preferences_general.xul
@@ -37,6 +37,7 @@
+
@@ -123,6 +124,7 @@
label="&zotero.preferences.automaticSnapshots;"
preference="pref-automaticSnapshots"/>
+
diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js
index c50cfdd0e3..10b74373d4 100644
--- a/chrome/content/zotero/xpcom/attachments.js
+++ b/chrome/content/zotero/xpcom/attachments.js
@@ -257,7 +257,7 @@ Zotero.Attachments = new function(){
* @param {String} [options.referrer]
* @param {CookieSandbox} [options.cookieSandbox]
* @param {Object} [options.saveOptions]
- * @return {Promise} - A promise for the created attachment item
+ * @return {Promise} - A promise for the created attachment item
*/
this.importFromURL = Zotero.Promise.coroutine(function* (options) {
var libraryID = options.libraryID;
@@ -298,7 +298,7 @@ Zotero.Attachments = new function(){
if (channel.responseStatus < 200 || channel.responseStatus >= 400) {
reject(new Error("Invalid response " + channel.responseStatus + " "
+ channel.responseStatusText + " for '" + url + "'"));
- return;
+ return false;
}
}
try {
diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js
index 7cb521b663..0c18c10c5e 100644
--- a/chrome/content/zotero/xpcom/collectionTreeView.js
+++ b/chrome/content/zotero/xpcom/collectionTreeView.js
@@ -2242,19 +2242,20 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
}
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
var targetLibraryID = targetTreeRow.ref.libraryID;
-
if (targetTreeRow.isCollection()) {
var parentCollectionID = targetTreeRow.ref.id;
}
else {
var parentCollectionID = false;
}
+ var addedItems = [];
for (var i=0; i {
+ return item
+ && item.isFileAttachment()
+ && item.attachmentContentType == 'application/pdf';
+ });
+ if (!pdfs.length) {
+ return;
+ }
+ this.recognizeItems(pdfs);
+ let pane = Zotero.getActiveZoteroPane();
+ if (pane) {
+ Zotero_RecognizePDF_Dialog.open();
+ }
+ };
+
/**
* Returns all rows
* @return {Array}
diff --git a/chrome/content/zotero/xpcom/server_connector.js b/chrome/content/zotero/xpcom/server_connector.js
index 5fd0b2fd76..c78f77b43d 100644
--- a/chrome/content/zotero/xpcom/server_connector.js
+++ b/chrome/content/zotero/xpcom/server_connector.js
@@ -649,7 +649,13 @@ Zotero.Server.Connector.SaveSnapshot.prototype = {
contentType: "application/pdf",
cookieSandbox
});
- yield session.addItem(item);
+ if (item) {
+ yield session.addItem(item);
+
+ // Automatically recognize PDF
+ Zotero.RecognizePDF.autoRecognizeItems([item]);
+ }
+
return 201;
}
catch (e) {
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 67f272a6d1..8ae802f58e 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -85,6 +85,7 @@ var ZoteroPane = new function()
// Set key down handler
document.getElementById('appcontent').addEventListener('keydown', ZoteroPane_Local.handleKeyDown, true);
+ // Hide or show the PDF recognizer button
Zotero.RecognizePDF.addListener('empty', function (row) {
document.getElementById('zotero-tb-recognize').hidden = true;
});
@@ -3692,6 +3693,7 @@ var ZoteroPane = new function()
files.push(file.path);
}
+ var addedItems = [];
var collection;
var fileBaseName;
if (parentItemID) {
@@ -3713,6 +3715,8 @@ var ZoteroPane = new function()
}
for (let file of files) {
+ let item;
+
if (link) {
// Rename linked file, with unique suffix if necessary
try {
@@ -3733,7 +3737,7 @@ var ZoteroPane = new function()
Zotero.logError(e);
}
- let item = yield Zotero.Attachments.linkFromFile({
+ item = yield Zotero.Attachments.linkFromFile({
file,
parentItemID,
collections: collection ? [collection] : undefined
@@ -3746,7 +3750,7 @@ var ZoteroPane = new function()
continue;
}
- yield Zotero.Attachments.importFromFile({
+ item = yield Zotero.Attachments.importFromFile({
file,
libraryID,
fileBaseName,
@@ -3754,6 +3758,13 @@ var ZoteroPane = new function()
collections: collection ? [collection] : undefined
});
}
+
+ addedItems.push(item);
+ }
+
+ // Automatically retrieve metadata for top-level PDFs
+ if (!parentItemID) {
+ Zotero.RecognizePDF.autoRecognizeItems(addedItems);
}
});
@@ -3917,6 +3928,9 @@ var ZoteroPane = new function()
});
+ /**
+ * @return {Zotero.Item|false} - The saved item, or false if item can't be saved
+ */
this.addItemFromURL = Zotero.Promise.coroutine(function* (url, itemType, saveSnapshot, row) {
if (window.content && url == window.content.document.location.href) {
return this.addItemFromPage(itemType, saveSnapshot, row);
@@ -3932,8 +3946,8 @@ var ZoteroPane = new function()
var processor = function (doc) {
return ZoteroPane_Local.addItemFromDocument(doc, itemType, saveSnapshot, row)
- .then(function () {
- deferred.resolve()
+ .then(function (item) {
+ deferred.resolve(item)
});
};
var done = function () {}
@@ -3966,7 +3980,7 @@ var ZoteroPane = new function()
if (!ZoteroPane_Local.canEdit(row)) {
ZoteroPane_Local.displayCannotEditLibraryMessage();
- return;
+ return false;
}
if (row !== undefined) {
@@ -3983,7 +3997,7 @@ var ZoteroPane = new function()
if (!ZoteroPane_Local.canEditFiles(row)) {
ZoteroPane_Local.displayCannotEditLibraryFilesMessage();
- return;
+ return false;
}
if (collectionTreeRow && collectionTreeRow.isCollection()) {
@@ -4000,7 +4014,7 @@ var ZoteroPane = new function()
contentType: mimeType
});
this.selectItem(attachmentItem.id)
- return;
+ return attachmentItem;
}
}
@@ -4033,7 +4047,7 @@ var ZoteroPane = new function()
}
}
- return item.id;
+ return item;
}
});
@@ -4521,6 +4535,12 @@ var ZoteroPane = new function()
};
+ this.recognizeSelected = function() {
+ Zotero.RecognizePDF.recognizeItems(ZoteroPane.getSelectedItems());
+ Zotero_RecognizePDF_Dialog.open();
+ };
+
+
this.createParentItemsFromSelected = Zotero.Promise.coroutine(function* () {
if (!this.canEdit()) {
this.displayCannotEditLibraryMessage();
@@ -4954,11 +4974,6 @@ var ZoteroPane = new function()
if(_beforeReloadFunctions.indexOf(func) === -1) _beforeReloadFunctions.push(func);
}
- this.recognizeSelected = function() {
- Zotero.RecognizePDF.recognizeItems(ZoteroPane.getSelectedItems());
- Zotero_RecognizePDF_Dialog.open();
- };
-
/**
* Implements nsIObserver for Zotero reload
*/
diff --git a/chrome/locale/en-US/zotero/preferences.dtd b/chrome/locale/en-US/zotero/preferences.dtd
index 9bb38feeac..b8dd7afb3c 100644
--- a/chrome/locale/en-US/zotero/preferences.dtd
+++ b/chrome/locale/en-US/zotero/preferences.dtd
@@ -27,6 +27,7 @@
+
diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js
index 38760ba7f4..9a6cc70c16 100644
--- a/defaults/preferences/zotero.js
+++ b/defaults/preferences/zotero.js
@@ -35,6 +35,7 @@ pref("extensions.zotero.automaticTags",true);
pref("extensions.zotero.fontSize", "1.0");
pref("extensions.zotero.layout", "standard");
pref("extensions.zotero.recursiveCollections", false);
+pref("extensions.zotero.autoRecognizeFiles", true);
pref("extensions.zotero.renameAttachmentFiles.automatic", true);
pref("extensions.zotero.renameAttachmentFiles.automatic.fileTypes", "application/pdf");
pref("extensions.zotero.attachmentRenameFormatString", '{%c - }{%y - }{%t{50}}');
diff --git a/test/content/support.js b/test/content/support.js
index e1c9efadcd..cba1158c07 100644
--- a/test/content/support.js
+++ b/test/content/support.js
@@ -19,6 +19,16 @@ function waitForDOMEvent(target, event, capture) {
return deferred.promise;
}
+async function waitForRecognizer() {
+ var win = await waitForWindow('chrome://zotero/content/recognizePDFDialog.xul')
+ // Wait for status to show as complete
+ var completeStr = Zotero.getString("recognizePDF.complete.label");
+ while (win.document.getElementById("label").value != completeStr) {
+ await Zotero.Promise.delay(20);
+ }
+ return win;
+}
+
/**
* Open a chrome window and return a promise for the window
*
diff --git a/test/tests/itemTreeViewTest.js b/test/tests/itemTreeViewTest.js
index ca485efb49..d7634dc2c4 100644
--- a/test/tests/itemTreeViewTest.js
+++ b/test/tests/itemTreeViewTest.js
@@ -695,11 +695,11 @@ describe("Zotero.ItemTreeView", function() {
file.append(pdfFilename);
pdfPath = file.path;
httpd.registerFile("/" + pdfFilename, file);
-
- Zotero.Prefs.clear('renameAttachmentFiles.automatic');
});
- afterEach(() => {
+ beforeEach(() => {
+ // Don't run recognize on every file
+ Zotero.Prefs.set('autoRecognizeFiles', false);
Zotero.Prefs.clear('renameAttachmentFiles.automatic');
});
@@ -707,6 +707,9 @@ describe("Zotero.ItemTreeView", function() {
var defer = new Zotero.Promise.defer();
httpd.stop(() => defer.resolve());
yield defer.promise;
+
+ Zotero.Prefs.clear('autoRecognizeFiles');
+ Zotero.Prefs.clear('renameAttachmentFiles.automatic');
});
it("should move a child item from one item to another", function* () {
@@ -879,6 +882,62 @@ describe("Zotero.ItemTreeView", function() {
);
});
+ it("should automatically retrieve metadata for top-level PDF if pref is enabled", async function () {
+ Zotero.Prefs.set('autoRecognizeFiles', true);
+
+ var view = zp.itemsView;
+
+ var promise = waitForItemEvent('add');
+ var recognizerPromise = waitForRecognizer();
+
+ // Fake recognizer response
+ Zotero.HTTP.mock = sinon.FakeXMLHttpRequest;
+ var server = sinon.fakeServer.create();
+ server.autoRespond = true;
+ setHTTPResponse(
+ server,
+ ZOTERO_CONFIG.RECOGNIZE_URL,
+ {
+ method: 'POST',
+ url: 'recognize',
+ status: 200,
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ json: {
+ title: 'Test',
+ authors: []
+ }
+ }
+ );
+
+ itemsView.drop(0, -1, {
+ dropEffect: 'copy',
+ effectAllowed: 'copy',
+ types: {
+ contains: function (type) {
+ return type == 'text/x-moz-url';
+ }
+ },
+ getData: function (type) {
+ if (type == 'text/x-moz-url') {
+ return pdfURL;
+ }
+ },
+ mozItemCount: 1,
+ })
+
+ var itemIDs = await promise;
+ var item = Zotero.Items.get(itemIDs[0]);
+
+ var progressWindow = await recognizerPromise;
+ progressWindow.close();
+ Zotero.RecognizePDF.cancel();
+ assert.isFalse(item.isTopLevelItem());
+
+ Zotero.HTTP.mock = null;
+ });
+
it("should rename a stored child attachment using parent metadata if no existing file attachments and pref enabled", async function () {
var view = zp.itemsView;
var parentTitle = Zotero.Utilities.randomString();
diff --git a/test/tests/server_connectorTest.js b/test/tests/server_connectorTest.js
index ab15218545..84975d7751 100644
--- a/test/tests/server_connectorTest.js
+++ b/test/tests/server_connectorTest.js
@@ -305,17 +305,36 @@ describe("Connector Server", function () {
assert.equal(item.getField('title'), 'Title');
});
- it("should save a PDF to the current selected collection", function* () {
- var collection = yield createDataObject('collection');
- yield waitForItemsLoad(win);
+ it("should save a PDF to the current selected collection and retrieve metadata", async function () {
+ var collection = await createDataObject('collection');
+ await waitForItemsLoad(win);
var file = getTestDataDirectory();
file.append('test.pdf');
httpd.registerFile("/test.pdf", file);
- var ids;
var promise = waitForItemEvent('add');
- yield Zotero.HTTP.request(
+ var recognizerPromise = waitForRecognizer();
+
+ var origRequest = Zotero.HTTP.request.bind(Zotero.HTTP);
+ var called = 0;
+ var stub = sinon.stub(Zotero.HTTP, 'request').callsFake(function (method, url, options) {
+ // Forward saveSnapshot request
+ if (url.endsWith('saveSnapshot')) {
+ return origRequest(...arguments);
+ }
+
+ // Fake recognizer response
+ return Zotero.Promise.resolve({
+ getResponseHeader: () => {},
+ responseText: JSON.stringify({
+ title: 'Test',
+ authors: []
+ })
+ });
+ });
+
+ await Zotero.HTTP.request(
'POST',
connectorServerPath + "/connector/saveSnapshot",
{
@@ -329,13 +348,20 @@ describe("Connector Server", function () {
}
);
- var ids = yield promise;
+ var ids = await promise;
assert.lengthOf(ids, 1);
var item = Zotero.Items.get(ids[0]);
assert.isTrue(item.isImportedAttachment());
assert.equal(item.attachmentContentType, 'application/pdf');
assert.isTrue(collection.hasItem(item.id));
+
+ var progressWindow = await recognizerPromise;
+ progressWindow.close();
+ Zotero.RecognizePDF.cancel();
+ assert.isFalse(item.isTopLevelItem());
+
+ stub.restore();
});
it("should respond with 500 if a read-only library is selected", function* () {