commit 5e706c31ada2e19c7b1516ad9f35c6eb71d4af4a
parent 6da0845f4b84b7214e68b1728e275d52e4655cef
Author: Adomas VenĨkauskas <adomas.ven@gmail.com>
Date: Mon, 1 Feb 2016 14:59:30 +0000
Translate and add items to library on drag
Diffstat:
12 files changed, 190 insertions(+), 87 deletions(-)
diff --git a/chrome/content/zotero/browser.js b/chrome/content/zotero/browser.js
@@ -640,6 +640,14 @@ var Zotero_Browser = new function() {
return;
}
+ if (Zotero.Feeds.get(libraryID)) {
+ Zotero_Browser.progress.changeHeadline(Zotero.getString("ingester.scrapeError"));
+ Zotero_Browser.progress.addDescription(Zotero.getString('save.error.cannotAddToFeed'));
+ Zotero_Browser.progress.show();
+ Zotero_Browser.progress.startCloseTimer(8000);
+ return;
+ }
+
if(Zotero.isConnector) {
Zotero.Connector.callMethod("getSelectedCollection", {}, function(response, status) {
if(status !== 200) {
diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js
@@ -1471,6 +1471,10 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
Zotero.debug("Top-level attachments and notes cannot be added to My Publications");
return false;
}
+ if(item instanceof Zotero.FeedItem) {
+ Zotero.debug("FeedItems cannot be added to My Publications");
+ return false;
+ }
skip = false;
continue;
}
@@ -1933,8 +1937,25 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
return;
}
+ var items = yield Zotero.Items.getAsync(ids);
+ if (!items) {
+ return;
+ }
+
+ if (items[0] instanceof Zotero.FeedItem) {
+ if (!(targetTreeRow.isCollection() || targetTreeRow.isLibrary() || targetTreeRow.isGroup())) {
+ return;
+ }
+
+ let promises = [];
+ for (let item of items) {
+ // No transaction, because most time is spent traversing urls
+ promises.push(item.translate(targetLibraryID, targetCollectionID))
+ }
+ return Zotero.Promise.all(promises);
+ }
+
if (targetTreeRow.isPublications()) {
- let items = yield Zotero.Items.getAsync(ids);
let io = this._treebox.treeBody.ownerDocument.defaultView
.ZoteroPane.showPublicationsWizard(items);
if (!io) {
@@ -1950,11 +1971,6 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
}
yield Zotero.DB.executeTransaction(function* () {
- var items = yield Zotero.Items.getAsync(ids);
- if (!items) {
- return;
- }
-
var newItems = [];
var newIDs = [];
var toMove = [];
diff --git a/chrome/content/zotero/xpcom/data/dataObjects.js b/chrome/content/zotero/xpcom/data/dataObjects.js
@@ -68,6 +68,10 @@ Zotero.defineProperty(Zotero.DataObjects.prototype, 'table', {
get: function() this._ZDO_table
});
+Zotero.defineProperty(Zotero.DataObjects.prototype, 'relationsTable', {
+ get: function() this._ZDO_object + 'Relations'
+});
+
Zotero.defineProperty(Zotero.DataObjects.prototype, 'primaryFields', {
get: function () Object.keys(this._primaryDataSQLParts)
}, {lazy: true});
diff --git a/chrome/content/zotero/xpcom/data/feedItem.js b/chrome/content/zotero/xpcom/data/feedItem.js
@@ -207,9 +207,9 @@ Zotero.FeedItem.prototype.forceEraseTx = function(options) {
* in the library
* @param libraryID {int} save item in library
* @param collectionID {int} add item to collection
- * @return {Promise<FeedItem>} translated feed item
+ * @return {Promise<FeedItem|Item>} translated feed item
*/
-Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (libaryID, collectionID) {
+Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (libraryID, collectionID) {
let deferred = Zotero.Promise.defer();
let error = function(e) { Zotero.debug(e, 1); deferred.reject(e); };
@@ -237,6 +237,12 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (libary
translate.setTranslator(translators[0]);
deferred = Zotero.Promise.defer();
+
+ if (libraryID) {
+ return translate.translate({libraryID, collections: collectionID ? [collectionID] : false})
+ .then(items => items ? items[0] : false);
+ }
+
// Clear these to prevent saving
translate.clearHandlers('itemDone');
translate.clearHandlers('itemsDone');
@@ -253,7 +259,10 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (libary
for (let field of deleteFields) {
delete itemData[field];
}
+ // TODO: handle no items like the ones in french history studies feed
// set new translated data for item
this.fromJSON(itemData);
this.forceSaveTx();
+
+ return this;
});
diff --git a/chrome/content/zotero/xpcom/data/feeds.js b/chrome/content/zotero/xpcom/data/feeds.js
@@ -105,7 +105,10 @@ Zotero.Feeds = new function() {
.map(id => Zotero.Libraries.get(id));
}
- this.get = Zotero.Libraries.get.bind(Zotero.Libraries);
+ this.get = function(libraryID) {
+ let library = Zotero.Libraries.get(libraryID);
+ return library.isFeed ? library : undefined;
+ }
this.haveFeeds = function() {
if (!this._cache) throw new Error("Zotero.Feeds cache is not initialized");
diff --git a/chrome/content/zotero/xpcom/data/relations.js b/chrome/content/zotero/xpcom/data/relations.js
@@ -219,8 +219,8 @@ Zotero.Relations = new function () {
// Get all object URIs except merge-tracking ones
let sql = "SELECT " + objectsClass.idColumn + " AS id, predicate, object "
- + "FROM " + type + "Relations "
- + "JOIN relationPredicates USING (predicateID) WHERE predicate != ?";
+ + "FROM " + objectsClass.relationsTable
+ + " JOIN relationPredicates USING (predicateID) WHERE predicate != ?";
let rows = yield Zotero.DB.queryAsync(sql, [this.replacedItemPredicate]);
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
diff --git a/chrome/content/zotero/xpcom/feedReader.js b/chrome/content/zotero/xpcom/feedReader.js
@@ -35,7 +35,7 @@
* http://rss.sciencedirect.com/publication/science/20925212
* http://www.ncbi.nlm.nih.gov/entrez/eutils/erss.cgi?rss_guid=1fmfIeN4X5Q8HemTZD5Rj6iu6-FQVCn7xc7_IPIIQtS1XiD9bf
* http://export.arxiv.org/rss/astro-ph
- * http://fhs.dukejournals.org/rss_feeds/recent.xml TODO: refreshing unreads all items
+ * http://fhs.dukejournals.org/rss_feeds/recent.xml
*/
/**
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
@@ -1377,7 +1377,7 @@ var ZoteroPane = new function()
if (item.isFeedItem) {
item.translate();
- this.startItemReadTimeout.bind(this, item.id);
+ this.startItemReadTimeout(item.id);
}
}
}
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
@@ -504,6 +504,7 @@ save.link.error = An error occurred while saving this link.
save.error.cannotMakeChangesToCollection = You cannot make changes to the currently selected collection.
save.error.cannotAddFilesToCollection = You cannot add files to the currently selected collection.
save.error.cannotAddToMyPublications = You cannot save items directly to My Publications. To add items to My Publications, drag them from another library.
+save.error.cannotAddToFeed = You cannot save items directly to feeds.
ingester.saveToZotero = Save to Zotero
ingester.saveToZoteroUsing = Save to Zotero using "%S"
diff --git a/test/tests/collectionTreeViewTest.js b/test/tests/collectionTreeViewTest.js
@@ -609,72 +609,106 @@ describe("Zotero.CollectionTreeView", function() {
// TODO: Check deeper subcollection open states
})
- })
-
- it("should move a subcollection and its subcollection up under another collection", function* () {
- var collectionA = yield createDataObject('collection', { name: "A" }, { skipSelect: true });
- var collectionB = yield createDataObject('collection', { name: "B", parentKey: collectionA.key });
- var collectionC = yield createDataObject('collection', { name: "C", parentKey: collectionB.key });
- var collectionD = yield createDataObject('collection', { name: "D" }, { skipSelect: true });
- var collectionE = yield createDataObject('collection', { name: "E" }, { skipSelect: true });
- var collectionF = yield createDataObject('collection', { name: "F" }, { skipSelect: true });
- var collectionG = yield createDataObject('collection', { name: "G", parentKey: collectionE.key });
- var collectionH = yield createDataObject('collection', { name: "H", parentKey: collectionG.key });
-
- var colIndexA = cv.getRowIndexByID('C' + collectionA.id);
- var colIndexB = cv.getRowIndexByID('C' + collectionB.id);
- var colIndexC = cv.getRowIndexByID('C' + collectionC.id);
- var colIndexD = cv.getRowIndexByID('C' + collectionD.id);
- var colIndexE = cv.getRowIndexByID('C' + collectionE.id);
- var colIndexF = cv.getRowIndexByID('C' + collectionF.id);
- var colIndexG = cv.getRowIndexByID('C' + collectionG.id);
- var colIndexH = cv.getRowIndexByID('C' + collectionH.id);
-
- yield cv.selectCollection(collectionG.id);
-
- // Add observer to wait for collection add
- var deferred = Zotero.Promise.defer();
- var observerID = Zotero.Notifier.registerObserver({
- notify: function (event, type, ids, extraData) {
- if (type == 'collection' && event == 'modify' && ids[0] == collectionG.id) {
- setTimeout(function () {
- deferred.resolve();
- }, 50);
+
+ it("should move a subcollection and its subcollection up under another collection", function* () {
+ var collectionA = yield createDataObject('collection', { name: "A" }, { skipSelect: true });
+ var collectionB = yield createDataObject('collection', { name: "B", parentKey: collectionA.key });
+ var collectionC = yield createDataObject('collection', { name: "C", parentKey: collectionB.key });
+ var collectionD = yield createDataObject('collection', { name: "D" }, { skipSelect: true });
+ var collectionE = yield createDataObject('collection', { name: "E" }, { skipSelect: true });
+ var collectionF = yield createDataObject('collection', { name: "F" }, { skipSelect: true });
+ var collectionG = yield createDataObject('collection', { name: "G", parentKey: collectionE.key });
+ var collectionH = yield createDataObject('collection', { name: "H", parentKey: collectionG.key });
+
+ var colIndexA = cv.getRowIndexByID('C' + collectionA.id);
+ var colIndexB = cv.getRowIndexByID('C' + collectionB.id);
+ var colIndexC = cv.getRowIndexByID('C' + collectionC.id);
+ var colIndexD = cv.getRowIndexByID('C' + collectionD.id);
+ var colIndexE = cv.getRowIndexByID('C' + collectionE.id);
+ var colIndexF = cv.getRowIndexByID('C' + collectionF.id);
+ var colIndexG = cv.getRowIndexByID('C' + collectionG.id);
+ var colIndexH = cv.getRowIndexByID('C' + collectionH.id);
+
+ yield cv.selectCollection(collectionG.id);
+
+ // Add observer to wait for collection add
+ var deferred = Zotero.Promise.defer();
+ var observerID = Zotero.Notifier.registerObserver({
+ notify: function (event, type, ids, extraData) {
+ if (type == 'collection' && event == 'modify' && ids[0] == collectionG.id) {
+ setTimeout(function () {
+ deferred.resolve();
+ }, 50);
+ }
}
- }
- }, 'collection', 'test');
-
- yield Zotero.Promise.delay(2000);
-
- yield drop(
- 'collection',
- {
- row: colIndexD,
- orient: 0
- },
- [collectionG.id],
- deferred.promise
- );
-
- Zotero.Notifier.unregisterObserver(observerID);
-
- var newColIndexA = cv.getRowIndexByID('C' + collectionA.id);
- var newColIndexB = cv.getRowIndexByID('C' + collectionB.id);
- var newColIndexC = cv.getRowIndexByID('C' + collectionC.id);
- var newColIndexD = cv.getRowIndexByID('C' + collectionD.id);
- var newColIndexE = cv.getRowIndexByID('C' + collectionE.id);
- var newColIndexF = cv.getRowIndexByID('C' + collectionF.id);
- var newColIndexG = cv.getRowIndexByID('C' + collectionG.id);
- var newColIndexH = cv.getRowIndexByID('C' + collectionH.id);
-
- assert.isFalse(cv.isContainerOpen(newColIndexE));
- assert.isTrue(cv.isContainerEmpty(newColIndexE));
- assert.isTrue(cv.isContainerOpen(newColIndexD));
- assert.isFalse(cv.isContainerEmpty(newColIndexD));
- assert.equal(newColIndexD, newColIndexG - 1);
- assert.equal(newColIndexG, newColIndexH - 1);
-
- // TODO: Check deeper subcollection open states
+ }, 'collection', 'test');
+
+ yield Zotero.Promise.delay(2000);
+
+ yield drop(
+ 'collection',
+ {
+ row: colIndexD,
+ orient: 0
+ },
+ [collectionG.id],
+ deferred.promise
+ );
+
+ Zotero.Notifier.unregisterObserver(observerID);
+
+ var newColIndexA = cv.getRowIndexByID('C' + collectionA.id);
+ var newColIndexB = cv.getRowIndexByID('C' + collectionB.id);
+ var newColIndexC = cv.getRowIndexByID('C' + collectionC.id);
+ var newColIndexD = cv.getRowIndexByID('C' + collectionD.id);
+ var newColIndexE = cv.getRowIndexByID('C' + collectionE.id);
+ var newColIndexF = cv.getRowIndexByID('C' + collectionF.id);
+ var newColIndexG = cv.getRowIndexByID('C' + collectionG.id);
+ var newColIndexH = cv.getRowIndexByID('C' + collectionH.id);
+
+ assert.isFalse(cv.isContainerOpen(newColIndexE));
+ assert.isTrue(cv.isContainerEmpty(newColIndexE));
+ assert.isTrue(cv.isContainerOpen(newColIndexD));
+ assert.isFalse(cv.isContainerEmpty(newColIndexD));
+ assert.equal(newColIndexD, newColIndexG - 1);
+ assert.equal(newColIndexG, newColIndexH - 1);
+
+ // TODO: Check deeper subcollection open states
+ })
+ })
+
+
+ describe("with feed items", function () {
+ it('should add a translated feed item recovered from an URL', function* (){
+ var feed = yield createFeed();
+ var collection = yield createDataObject('collection', false, { skipSelect: true });
+ var url = getTestDataItemUrl('metadata/journalArticle-single.html');
+ var feedItem = yield createDataObject('feedItem', {libraryID: feed.libraryID}, { skipSelect: true });
+ feedItem.setField('url', url);
+ yield feedItem.forceSaveTx();
+ var translateFn = sinon.spy(feedItem, 'translate');
+
+ // Add observer to wait for collection add
+ var deferred = Zotero.Promise.defer();
+ var itemIds;
+
+ var ids = (yield drop('item', 'C' + collection.id, [feedItem.id])).ids;
+
+ // Check that the translated item was the one that was created after drag
+ var item;
+ yield translateFn.returnValues[0].then(function(i) {
+ item = i;
+ assert.equal(item.id, ids[0]);
+ });
+
+ yield cv.selectCollection(collection.id);
+ yield waitForItemsLoad(win);
+
+ var itemsView = win.ZoteroPane.itemsView;
+ assert.equal(itemsView.rowCount, 1);
+ var treeRow = itemsView.getRow(0);
+ assert.equal(treeRow.ref.id, item.id);
+ })
})
})
})
diff --git a/test/tests/feedItemTest.js b/test/tests/feedItemTest.js
@@ -194,9 +194,7 @@ describe("Zotero.FeedItem", function () {
describe("#toggleRead()", function() {
it('should toggle state', function* () {
- feed = yield createFeed();
-
- let item = yield createDataObject('feedItem', { guid: Zotero.randomString(), libraryID: feed.id });
+ let item = yield createDataObject('feedItem', { libraryID });
item.isRead = false;
yield item.forceSaveTx();
@@ -204,9 +202,7 @@ describe("Zotero.FeedItem", function () {
assert.isTrue(item.isRead, "item is toggled to read state");
});
it('should save if specified state is different from current', function* (){
- feed = yield createFeed();
-
- let item = yield createDataObject('feedItem', { guid: Zotero.randomString(), libraryID: feed.id });
+ let item = yield createDataObject('feedItem', { libraryID });
item.isRead = false;
yield item.forceSaveTx();
sinon.spy(item, 'save');
@@ -220,4 +216,36 @@ describe("Zotero.FeedItem", function () {
assert.isFalse(item.save.called, "item was not saved on toggle read to same state");
});
});
+
+ describe('#translate()', function() {
+ before(function* () {
+ // Needs an open window to be able to create a hidden window for translation
+ yield loadBrowserWindow();
+ });
+ it('translates and saves items', function* () {
+ var feedItem = yield createDataObject('feedItem', {libraryID});
+ var url = getTestDataItemUrl('metadata/journalArticle-single.html');
+ feedItem.setField('url', url);
+ yield feedItem.forceSaveTx();
+
+ yield feedItem.translate();
+
+ assert.equal(feedItem.getField('title'), 'Scarcity or Abundance? Preserving the Past in a Digital Era');
+ });
+ it('translates and saves items to corresponding library and collection', function* () {
+ let group = yield createGroup();
+ let collection = yield createDataObject('collection', {libraryID: group.libraryID});
+
+ var feedItem = yield createDataObject('feedItem', {libraryID});
+ var url = getTestDataItemUrl('metadata/journalArticle-single.html');
+ feedItem.setField('url', url);
+ yield feedItem.forceSaveTx();
+
+ yield feedItem.translate(group.libraryID, collection.id);
+
+ let item = collection.getChildItems(false, false)[0];
+
+ assert.equal(item.getField('title'), 'Scarcity or Abundance? Preserving the Past in a Digital Era');
+ });
+ });
});
diff --git a/test/tests/feedTest.js b/test/tests/feedTest.js
@@ -250,10 +250,10 @@ describe("Zotero.Feed", function() {
feed._feedUrl = feedUrl;
yield feed.updateFeed();
- let feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
+ let feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
feedItem.isRead = true;
yield feedItem.forceSaveTx();
- feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
+ feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
assert.isTrue(feedItem.isRead);
let oldDateModified = feedItem.dateModified;
@@ -261,7 +261,7 @@ describe("Zotero.Feed", function() {
feed._feedUrl = modifiedFeedUrl;
yield feed.updateFeed();
- feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573");
+ feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
assert.notEqual(oldDateModified, feedItem.dateModified);
assert.isFalse(feedItem.isRead)