diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml index c2f1bdb98..02e4e796f 100644 --- a/chrome/content/zotero/bindings/itembox.xml +++ b/chrome/content/zotero/bindings/itembox.xml @@ -341,7 +341,9 @@ fieldNames.push(Zotero.ItemFields.getName(fields[i])); } - fieldNames.push("dateAdded", "dateModified"); + if (! (this.item instanceof Zotero.FeedItem)) { + fieldNames.push("dateAdded", "dateModified"); + } } for (var i=0; i non-feed) - if (! this.collectionTreeRow.isFeed() && colId) { - col = this._treebox.columns.getNamedColumn(colId); - dir = Zotero.Prefs.get('itemTree.sortDirection'); - Zotero.Prefs.clear('itemTree.sortColumnId'); - Zotero.Prefs.clear('itemTree.sortDirection'); - // Sort Feeds by dateAdded (anything -> feed) - } else if (this.collectionTreeRow.isFeed()) { - col = this._treebox.columns.getNamedColumn("zotero-items-column-dateAdded"); - dir = 'descending'; - // No previous sort setting stored, so store it (non-feed -> feed) - if (!colId && currentCol) { - Zotero.Prefs.set('itemTree.sortColumnId', currentCol.id); - Zotero.Prefs.set('itemTree.sortDirection', currentDir); - } - // Retain current sort setting (non-feed -> non-feed) - } else { - col = currentCol; - dir = currentDir; - } - if (col) { - col.element.setAttribute('sortActive', true); - col.element.setAttribute('sortDirection', dir); - } -} - - /** * Reload the rows from the data access methods * (doesn't call the tree.invalidate methods, etc.) @@ -2130,9 +2087,12 @@ Zotero.ItemTreeView.prototype.getSortedItems = function(asIDs) { Zotero.ItemTreeView.prototype.getSortField = function() { - var column = this._treebox.columns.getSortedColumn() + if (this.collectionTreeRow.isFeed()) { + return 'id'; + } + var column = this._treebox.columns.getSortedColumn(); if (!column) { - column = this._treebox.columns.getFirstColumn() + column = this._treebox.columns.getFirstColumn(); } // zotero-items-column-_________ return column.id.substring(20); @@ -2176,6 +2136,9 @@ Zotero.ItemTreeView.prototype.getSortFields = function () { * Returns 'ascending' or 'descending' */ Zotero.ItemTreeView.prototype.getSortDirection = function() { + if (this.collectionTreeRow.isFeed) { + return Zotero.Prefs.get('feedSortAsc') ? 'asc' : 'desc'; + } var column = this._treebox.columns.getSortedColumn(); if (!column) { return 'ascending'; diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js index 7bfc9b040..da30fa072 100644 --- a/chrome/content/zotero/xpcom/schema.js +++ b/chrome/content/zotero/xpcom/schema.js @@ -2188,9 +2188,6 @@ Zotero.Schema = new function(){ yield Zotero.DB.queryAsync("DROP TABLE tagsOld"); yield Zotero.DB.queryAsync("DROP TABLE librariesOld"); - // Feeds - yield Zotero.DB.queryAsync("CREATE TABLE feeds (\n libraryID INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n url TEXT NOT NULL UNIQUE,\n lastUpdate TIMESTAMP,\n lastCheck TIMESTAMP,\n lastCheckError TEXT,\n cleanupAfter INT,\n refreshInterval INT,\n FOREIGN KEY (libraryID) REFERENCES libraries(libraryID) ON DELETE CASCADE\n)"); - yield Zotero.DB.queryAsync("CREATE TABLE feedItems (\n itemID INTEGER PRIMARY KEY,\n guid TEXT NOT NULL UNIQUE,\n readTime TIMESTAMP,\n FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE\n)"); } if (i == 81) { @@ -2214,6 +2211,14 @@ Zotero.Schema = new function(){ yield Zotero.DB.queryAsync("INSERT INTO itemTypeFields VALUES (17, 98, NULL, 8)"); yield Zotero.DB.queryAsync("INSERT INTO itemTypeFields VALUES (17, 42, NULL, 9)"); } + + if (i == 83) { + // Feeds + yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS feeds"); + yield Zotero.DB.queryAsync("DROP TABLE IF EXISTS feedItems"); + yield Zotero.DB.queryAsync("CREATE TABLE feeds (\n libraryID INTEGER PRIMARY KEY,\n name TEXT NOT NULL,\n url TEXT NOT NULL UNIQUE,\n lastUpdate TIMESTAMP,\n lastCheck TIMESTAMP,\n lastCheckError TEXT,\n lastGUID TEXT,\n cleanupAfter INT,\n refreshInterval INT,\n FOREIGN KEY (libraryID) REFERENCES libraries(libraryID) ON DELETE CASCADE\n)"); + yield Zotero.DB.queryAsync("CREATE TABLE feedItems (\n itemID INTEGER PRIMARY KEY,\n guid TEXT NOT NULL UNIQUE,\n readTime TIMESTAMP,\n translatedTime TIMESTAMP,\n FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE\n)"); + } } yield _updateDBVersion('userdata', toVersion); diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index b36d084a3..5be02a999 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -1376,7 +1376,9 @@ var ZoteroPane = new function() } if (item.isFeedItem) { - item.translate(); + if (! item.isTranslated) { + item.translate(); + } this.startItemReadTimeout(item.id); } } diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index c748b99b4..70dc4cb87 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -62,6 +62,7 @@ pref("extensions.zotero.lastLongTagMode", 0); pref("extensions.zotero.lastLongTagDelimiter", ";"); pref("extensions.zotero.fallbackSort", 'firstCreator,date,title,dateAdded'); +pref("extensions.zotero.feedSortAsc", false); pref("extensions.zotero.sortCreatorAsString", false); //Tag Cloud diff --git a/resource/schema/userdata.sql b/resource/schema/userdata.sql index bd0ba0467..12a5e3384 100644 --- a/resource/schema/userdata.sql +++ b/resource/schema/userdata.sql @@ -1,4 +1,4 @@ --- 82 +-- 83 -- Copyright (c) 2009 Center for History and New Media -- George Mason University, Fairfax, Virginia, USA @@ -203,6 +203,7 @@ CREATE TABLE feeds ( lastUpdate TIMESTAMP, lastCheck TIMESTAMP, lastCheckError TEXT, + lastGUID TEXT, cleanupAfter INT, refreshInterval INT, FOREIGN KEY (libraryID) REFERENCES libraries(libraryID) ON DELETE CASCADE @@ -212,6 +213,7 @@ CREATE TABLE feedItems ( itemID INTEGER PRIMARY KEY, guid TEXT NOT NULL UNIQUE, readTime TIMESTAMP, + translatedTime TIMESTAMP, FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE ); diff --git a/test/tests/data/feed.rss b/test/tests/data/feed.rss index faecc47ea..8b732094a 100644 --- a/test/tests/data/feed.rss +++ b/test/tests/data/feed.rss @@ -19,11 +19,6 @@ Tue, 03 Jun 2003 09:39:21 GMT http://liftoff.msfc.nasa.gov/2003/06/03.html#item573 - - Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st. - Fri, 30 May 2003 11:06:42 GMT - http://liftoff.msfc.nasa.gov/2003/05/30.html#item572 - The Engine That Does More http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp diff --git a/test/tests/data/feedModified.rss b/test/tests/data/feedModified.rss index 9e7e0fff1..015463082 100644 --- a/test/tests/data/feedModified.rss +++ b/test/tests/data/feedModified.rss @@ -13,17 +13,17 @@ editor@example.com webmaster@example.com - Star City + Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st. + Fri, 30 May 2003 11:06:42 GMT + http://liftoff.msfc.nasa.gov/2003/05/30.html#item572 + + + Star City (Updated) http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's <a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star City</a>. Tue, 03 Jun 2037 09:39:21 GMT http://liftoff.msfc.nasa.gov/2003/06/03.html#item573 - - Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st. - Fri, 30 May 2003 11:06:42 GMT - http://liftoff.msfc.nasa.gov/2003/05/30.html#item572 - The Engine That Does More http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp diff --git a/test/tests/feedReaderTest.js b/test/tests/feedReaderTest.js index c262a8d75..932930315 100644 --- a/test/tests/feedReaderTest.js +++ b/test/tests/feedReaderTest.js @@ -111,14 +111,13 @@ describe("Zotero.FeedReader", function () { title: 'Star City', abstractNote: 'How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia\'s Star City.', url: 'http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp', - dateModified: '2003-06-03 09:39:21', - dateAdded: '2003-06-03 09:39:21', creators: [{ firstName: '', lastName: 'editor@example.com', creatorType: 'author', fieldMode: 1 }], + date: 'Tue, 03 Jun 2003 09:39:21 GMT', language: 'en-us', itemType: 'journalArticle' }; @@ -136,8 +135,6 @@ describe("Zotero.FeedReader", function () { title: 'Title 1', abstractNote: 'Description 1', url: 'http://www.example.com/item1', - dateModified: '2016-01-07 00:00:00', - dateAdded: '2016-01-07 00:00:00', creators: [ { firstName: 'Author1 A. T.', lastName: 'Rohtua', creatorType: 'author' }, { firstName: 'Author2 A.', lastName: 'Auth', creatorType: 'author' }, diff --git a/test/tests/feedTest.js b/test/tests/feedTest.js index 96cf9bc44..8e80930dc 100644 --- a/test/tests/feedTest.js +++ b/test/tests/feedTest.js @@ -206,9 +206,16 @@ describe("Zotero.Feed", function() { }); describe('#updateFeed()', function() { + var feed; var feedUrl = getTestDataItemUrl("feed.rss"); var modifiedFeedUrl = getTestDataItemUrl("feedModified.rss"); + beforeEach(function* (){ + feed = yield createFeed(); + feed._feedUrl = feedUrl; + yield feed.updateFeed(); + }); + afterEach(function* () { yield clearFeeds(); }); @@ -225,15 +232,11 @@ describe("Zotero.Feed", function() { }); it('should add new feed items', function* () { - let feed = yield createFeed(); - feed._feedUrl = feedUrl; - yield feed.updateFeed(); - let feedItems = yield Zotero.FeedItems.getAll(feed.id); - assert.equal(feedItems.length, 4); + assert.equal(feedItems.length, 3); }); - it('should set lastCheck and lastUpdated values', function* () { + it('should set lastCheck, lastUpdated and lastGUID values', function* () { let feed = yield createFeed(); feed._feedUrl = feedUrl; @@ -244,61 +247,36 @@ describe("Zotero.Feed", function() { assert.ok(feed.lastCheck >= Zotero.Date.dateToSQL(new Date(Date.now() - 1000*60), true)); assert.ok(feed.lastUpdate >= Zotero.Date.dateToSQL(new Date(Date.now() - 1000*60), true)); + assert.equal(feed.lastGUID, 'http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:'+feed.id); }); it('should update modified items and set unread', function* () { - let feed = yield createFeed(); - feed._feedUrl = feedUrl; - yield feed.updateFeed(); - 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:"+feed.id); assert.isTrue(feedItem.isRead); - let oldDateModified = feedItem.dateModified; + let oldDateModified = feedItem.getField('date'); feed._feedUrl = modifiedFeedUrl; yield feed.updateFeed(); feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id); - assert.notEqual(oldDateModified, feedItem.dateModified); + assert.notEqual(oldDateModified, feedItem.getField('date')); assert.isFalse(feedItem.isRead) }); it('should skip items that are not modified', function* () { - let feed = yield createFeed(); - feed._feedUrl = feedUrl; - yield feed.updateFeed(); - - let feedItems = yield Zotero.FeedItems.getAll(feed.id); - let datesAdded = [], datesModified = []; - for(let feedItem of feedItems) { - datesAdded.push(feedItem.dateAdded); - datesModified.push(feedItem.dateModified); - } + let save = sinon.spy(Zotero.FeedItem.prototype, 'save'); feed._feedUrl = modifiedFeedUrl; yield feed.updateFeed(); - feedItems = yield Zotero.FeedItems.getAll(feed.id); - - let changedCount = 0; - for (let i = 0; i < feedItems.length; i++) { - assert.equal(feedItems[i].dateAdded, datesAdded[i]); - if (feedItems[i].dateModified != datesModified[i]) { - changedCount++; - } - } - - assert.equal(changedCount, 1); + assert.equal(save.thisValues[0].guid, "http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id); + save.restore(); }); it('should update unread count', function* () { - let feed = yield createFeed(); - feed._feedUrl = feedUrl; - yield feed.updateFeed(); - - assert.equal(feed.unreadCount, 4); + assert.equal(feed.unreadCount, 3); let feedItems = yield Zotero.FeedItems.getAll(feed.id); for (let feedItem of feedItems) { @@ -309,7 +287,22 @@ describe("Zotero.Feed", function() { feed._feedUrl = modifiedFeedUrl; yield feed.updateFeed(); - assert.equal(feed.unreadCount, 1); + assert.equal(feed.unreadCount, 2); + }); + it('should not re-add deleted items, but add new ones', function* () { + let feedItems = yield Zotero.FeedItems.getAll(feed.id); + yield feedItems[1].forceEraseTx(); + + feedItems = yield Zotero.FeedItems.getAll(feed.id); + for (let feedItem of feedItems) { + feedItem.isRead = true; + yield feedItem.forceSaveTx(); + } + + feed._feedUrl = modifiedFeedUrl; + yield feed.updateFeed(); + + assert.equal(feed.unreadCount, 2); }); });