Various feeds changes
- Change sort order for feed items to natural order - Remove display of dates in itembox - Trim html tags from creators in FeedReader parser
This commit is contained in:
parent
5e706c31ad
commit
e206b0af5e
14 changed files with 118 additions and 192 deletions
|
@ -341,7 +341,9 @@
|
||||||
fieldNames.push(Zotero.ItemFields.getName(fields[i]));
|
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<fieldNames.length; i++) {
|
for (var i=0; i<fieldNames.length; i++) {
|
||||||
|
|
|
@ -85,7 +85,7 @@ Zotero.defineProperty(Zotero.Feed, '_unreadCountSQL', {
|
||||||
|
|
||||||
Zotero.defineProperty(Zotero.Feed, '_dbColumns', {
|
Zotero.defineProperty(Zotero.Feed, '_dbColumns', {
|
||||||
value: Object.freeze(['name', 'url', 'lastUpdate', 'lastCheck',
|
value: Object.freeze(['name', 'url', 'lastUpdate', 'lastCheck',
|
||||||
'lastCheckError', 'cleanupAfter', 'refreshInterval'])
|
'lastCheckError', 'lastGUID', 'cleanupAfter', 'refreshInterval'])
|
||||||
});
|
});
|
||||||
|
|
||||||
Zotero.defineProperty(Zotero.Feed, '_primaryDataSQLParts');
|
Zotero.defineProperty(Zotero.Feed, '_primaryDataSQLParts');
|
||||||
|
@ -130,7 +130,7 @@ for (let i=0; i<accessors.length; i++) {
|
||||||
set: function(v) this._set(prop, v)
|
set: function(v) this._set(prop, v)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let getters = ['lastCheck', 'lastUpdate', 'lastCheckError'];
|
let getters = ['lastCheck', 'lastUpdate', 'lastCheckError', 'lastGUID'];
|
||||||
for (let i=0; i<getters.length; i++) {
|
for (let i=0; i<getters.length; i++) {
|
||||||
let name = getters[i];
|
let name = getters[i];
|
||||||
let prop = Zotero.Feed._colToProp(name);
|
let prop = Zotero.Feed._colToProp(name);
|
||||||
|
@ -212,6 +212,7 @@ Zotero.Feed.prototype._loadDataFromRow = function(row) {
|
||||||
this._feedLastCheckError = row._feedLastCheckError || null;
|
this._feedLastCheckError = row._feedLastCheckError || null;
|
||||||
this._feedLastCheck = row._feedLastCheck || null;
|
this._feedLastCheck = row._feedLastCheck || null;
|
||||||
this._feedLastUpdate = row._feedLastUpdate || null;
|
this._feedLastUpdate = row._feedLastUpdate || null;
|
||||||
|
this._feedLastGUID = row._feedLastGUID || null;
|
||||||
this._feedCleanupAfter = parseInt(row._feedCleanupAfter) || null;
|
this._feedCleanupAfter = parseInt(row._feedCleanupAfter) || null;
|
||||||
this._feedRefreshInterval = parseInt(row._feedRefreshInterval) || null;
|
this._feedRefreshInterval = parseInt(row._feedRefreshInterval) || null;
|
||||||
this._feedUnreadCount = parseInt(row._feedUnreadCount);
|
this._feedUnreadCount = parseInt(row._feedUnreadCount);
|
||||||
|
@ -328,6 +329,7 @@ Zotero.Feed.prototype.clearExpiredItems = Zotero.Promise.coroutine(function* ()
|
||||||
|
|
||||||
Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () {
|
Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () {
|
||||||
var toAdd = [];
|
var toAdd = [];
|
||||||
|
var createNew = true;
|
||||||
if (this._updating) {
|
if (this._updating) {
|
||||||
return this._updating;
|
return this._updating;
|
||||||
}
|
}
|
||||||
|
@ -343,20 +345,16 @@ Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () {
|
||||||
let itemIterator = new fr.ItemIterator();
|
let itemIterator = new fr.ItemIterator();
|
||||||
let item, processedGUIDs = [];
|
let item, processedGUIDs = [];
|
||||||
while (item = yield itemIterator.next().value) {
|
while (item = yield itemIterator.next().value) {
|
||||||
// NOTE: Might cause issues with feeds that set pubDate for publication date of the item
|
// Append id at the end to prevent same item collisions from different feeds
|
||||||
// rather than the date the item was added to the feed.
|
// when to terminate item retrieval.
|
||||||
if (item.dateModified && this.lastUpdate
|
item.guid += ":" + this.id;
|
||||||
&& item.dateModified < this.lastUpdate
|
if (item.guid == this.lastGUID) {
|
||||||
) {
|
Zotero.debug("Feed#update: last seen item reached (" + this.lastGUID + ")");
|
||||||
Zotero.debug("Item modification date before last update date (" + this.lastCheck + ")");
|
|
||||||
Zotero.debug(item);
|
Zotero.debug(item);
|
||||||
// We can stop now
|
// Don't create new items (expired and deleted), but update existing ones
|
||||||
fr.terminate();
|
createNew = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append id at the end to prevent same item collisions from different feeds
|
|
||||||
item.guid += ":" + this.id;
|
|
||||||
if (processedGUIDs.indexOf(item.guid) != -1) {
|
if (processedGUIDs.indexOf(item.guid) != -1) {
|
||||||
Zotero.debug("Feed item " + item.guid + " already processed from feed.");
|
Zotero.debug("Feed item " + item.guid + " already processed from feed.");
|
||||||
continue;
|
continue;
|
||||||
|
@ -367,30 +365,29 @@ Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () {
|
||||||
Zotero.debug(item, 5);
|
Zotero.debug(item, 5);
|
||||||
|
|
||||||
let feedItem = yield Zotero.FeedItems.getAsyncByGUID(item.guid);
|
let feedItem = yield Zotero.FeedItems.getAsyncByGUID(item.guid);
|
||||||
if (!feedItem) {
|
if (!feedItem && createNew) {
|
||||||
feedItem = new Zotero.FeedItem();
|
feedItem = new Zotero.FeedItem();
|
||||||
feedItem.guid = item.guid;
|
feedItem.guid = item.guid;
|
||||||
feedItem.libraryID = this.id;
|
feedItem.libraryID = this.id;
|
||||||
} else {
|
} else if(! feedItem.isTranslated) {
|
||||||
Zotero.debug("Feed item " + item.guid + " already in library.");
|
Zotero.debug("Feed item " + item.guid + " already in library.");
|
||||||
|
|
||||||
if (!item.dateModified ||
|
|
||||||
(feedItem.dateModified && feedItem.dateModified == item.dateModified)
|
|
||||||
) {
|
|
||||||
Zotero.debug("Modification date has not changed. Skipping update.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Zotero.debug("Updating metadata");
|
Zotero.debug("Updating metadata");
|
||||||
yield feedItem.loadItemData();
|
yield feedItem.loadItemData();
|
||||||
yield feedItem.loadCreators();
|
yield feedItem.loadCreators();
|
||||||
feedItem.isRead = false;
|
} else {
|
||||||
|
// Either has been translated or beyond lastGUID
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete invalid data
|
// Delete invalid data
|
||||||
delete item.guid;
|
delete item.guid;
|
||||||
delete item.dateAdded;
|
|
||||||
|
|
||||||
feedItem.fromJSON(item);
|
feedItem.fromJSON(item);
|
||||||
|
|
||||||
|
if (!feedItem.hasChanged()) {
|
||||||
|
Zotero.debug("Feed item " + feedItem.guid + " has not changed");
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
feedItem.isRead = false;
|
||||||
toAdd.push(feedItem);
|
toAdd.push(feedItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,6 +408,7 @@ Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this._set('_feedLastUpdate', Zotero.Date.dateToSQL(new Date(), true));
|
this._set('_feedLastUpdate', Zotero.Date.dateToSQL(new Date(), true));
|
||||||
|
this._set('_feedLastGUID', toAdd[0].guid);
|
||||||
}
|
}
|
||||||
this._set('_feedLastCheck', Zotero.Date.dateToSQL(new Date(), true));
|
this._set('_feedLastCheck', Zotero.Date.dateToSQL(new Date(), true));
|
||||||
yield this.saveTx();
|
yield this.saveTx();
|
||||||
|
|
|
@ -31,6 +31,7 @@ Zotero.FeedItem = function(itemTypeOrID, params = {}) {
|
||||||
Zotero.FeedItem._super.call(this, itemTypeOrID);
|
Zotero.FeedItem._super.call(this, itemTypeOrID);
|
||||||
|
|
||||||
this._feedItemReadTime = null;
|
this._feedItemReadTime = null;
|
||||||
|
this._feedItemTranslatedTime = null;
|
||||||
|
|
||||||
Zotero.Utilities.assignProps(this, params, ['guid']);
|
Zotero.Utilities.assignProps(this, params, ['guid']);
|
||||||
};
|
};
|
||||||
|
@ -70,21 +71,21 @@ Zotero.defineProperty(Zotero.FeedItem.prototype, 'isRead', {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//
|
//
|
||||||
//Zotero.defineProperty(Zotero.FeedItem.prototype, 'isTranslated', {
|
Zotero.defineProperty(Zotero.FeedItem.prototype, 'isTranslated', {
|
||||||
// get: function() {
|
get: function() {
|
||||||
// return !!this._feedItemTranslationTime;
|
return !!this._feedItemTranslatedTime;
|
||||||
// },
|
},
|
||||||
// set: function(state) {
|
set: function(state) {
|
||||||
// if (state != !!this._feedItemTranslationTime) {
|
if (state != !!this._feedItemTranslatedTime) {
|
||||||
// if (state) {
|
if (state) {
|
||||||
// this._feedItemTranslationTime = Zotero.Date.dateToSQL(new Date(), true);
|
this._feedItemTranslatedTime = Zotero.Date.dateToSQL(new Date(), true);
|
||||||
// } else {
|
} else {
|
||||||
// this._feedItemTranslationTime = null;
|
this._feedItemTranslatedTime = null;
|
||||||
// }
|
}
|
||||||
// this._changed.feedItemData = true;
|
this._changed.feedItemData = true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//});
|
});
|
||||||
|
|
||||||
Zotero.FeedItem.prototype.loadPrimaryData = Zotero.Promise.coroutine(function* (reload, failOnMissing) {
|
Zotero.FeedItem.prototype.loadPrimaryData = Zotero.Promise.coroutine(function* (reload, failOnMissing) {
|
||||||
if (this.guid && !this.id) {
|
if (this.guid && !this.id) {
|
||||||
|
@ -166,17 +167,12 @@ Zotero.FeedItem.prototype.forceSaveTx = function(options) {
|
||||||
return this.saveTx(newOptions);
|
return this.saveTx(newOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
Zotero.FeedItem.prototype.save = function(options = {}) {
|
|
||||||
options.skipDateModifiedUpdate = true;
|
|
||||||
return Zotero.FeedItem._super.prototype.save.apply(this, arguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
Zotero.FeedItem.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
Zotero.FeedItem.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
yield Zotero.FeedItem._super.prototype._saveData.apply(this, arguments);
|
yield Zotero.FeedItem._super.prototype._saveData.apply(this, arguments);
|
||||||
|
|
||||||
if (this._changed.feedItemData || env.isNew) {
|
if (this._changed.feedItemData || env.isNew) {
|
||||||
var sql = "REPLACE INTO feedItems VALUES (?,?,?)";
|
var sql = "REPLACE INTO feedItems VALUES (?,?,?,?)";
|
||||||
yield Zotero.DB.queryAsync(sql, [env.id, this.guid, this._feedItemReadTime]);
|
yield Zotero.DB.queryAsync(sql, [env.id, this.guid, this._feedItemReadTime, this._feedItemTranslatedTime]);
|
||||||
|
|
||||||
this._clearChanged('feedItemData');
|
this._clearChanged('feedItemData');
|
||||||
}
|
}
|
||||||
|
@ -262,6 +258,7 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
||||||
// TODO: handle no items like the ones in french history studies feed
|
// TODO: handle no items like the ones in french history studies feed
|
||||||
// set new translated data for item
|
// set new translated data for item
|
||||||
this.fromJSON(itemData);
|
this.fromJSON(itemData);
|
||||||
|
this.isTranslated = true;
|
||||||
this.forceSaveTx();
|
this.forceSaveTx();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -40,6 +40,7 @@ Zotero.FeedItems = new Proxy(function() {
|
||||||
let obj = zi_primaryDataSQLParts.call(this);
|
let obj = zi_primaryDataSQLParts.call(this);
|
||||||
obj.feedItemGUID = "FeI.guid AS feedItemGUID";
|
obj.feedItemGUID = "FeI.guid AS feedItemGUID";
|
||||||
obj.feedItemReadTime = "FeI.readTime AS feedItemReadTime";
|
obj.feedItemReadTime = "FeI.readTime AS feedItemReadTime";
|
||||||
|
obj.feedItemTranslatedTime = "FeI.translatedTime AS feedItemTranslatedTime";
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}, {lazy: true});
|
}, {lazy: true});
|
||||||
|
|
|
@ -289,7 +289,7 @@ Zotero.FeedReader._processCreators = function(feedEntry, field, role) {
|
||||||
let person = personArr.queryElementAt(i, Components.interfaces.nsIFeedPerson);
|
let person = personArr.queryElementAt(i, Components.interfaces.nsIFeedPerson);
|
||||||
if (!person || !person.name) continue;
|
if (!person || !person.name) continue;
|
||||||
|
|
||||||
let name = Zotero.Utilities.trimInternal(person.name);
|
let name = Zotero.Utilities.cleanTags(Zotero.Utilities.trimInternal(person.name));
|
||||||
if (!name) continue;
|
if (!name) continue;
|
||||||
|
|
||||||
let commas = name.split(',').length - 1,
|
let commas = name.split(',').length - 1,
|
||||||
|
@ -336,6 +336,10 @@ Zotero.FeedReader._processCreators = function(feedEntry, field, role) {
|
||||||
if (!creator.firstName) {
|
if (!creator.firstName) {
|
||||||
creator.fieldMode = 1;
|
creator.fieldMode = 1;
|
||||||
}
|
}
|
||||||
|
// Sometimes these end up empty when parsing really nasty HTML based fields, so just skip.
|
||||||
|
if (!creator.firstName && !creator.lastName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
creators.push(creator);
|
creators.push(creator);
|
||||||
}
|
}
|
||||||
|
@ -376,43 +380,6 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
|
||||||
|
|
||||||
if (feedEntry.link) item.url = feedEntry.link.spec;
|
if (feedEntry.link) item.url = feedEntry.link.spec;
|
||||||
|
|
||||||
if (feedEntry.updated) item.dateModified = new Date(feedEntry.updated);
|
|
||||||
|
|
||||||
if (feedEntry.published) {
|
|
||||||
var date = new Date(feedEntry.published);
|
|
||||||
|
|
||||||
if (!date.getUTCSeconds() && !(date.getUTCHours() && date.getUTCMinutes())) {
|
|
||||||
// There was probably no time, but there may have been a a date range,
|
|
||||||
// so something could have ended up in the hour _or_ minute field
|
|
||||||
date = getFeedField(feedEntry, 'pubDate')
|
|
||||||
/* In case it was magically pulled from some other field */
|
|
||||||
|| ( date.getUTCFullYear() + '-'
|
|
||||||
+ (date.getUTCMonth() + 1) + '-'
|
|
||||||
+ date.getUTCDate() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
date = Zotero.Date.dateToSQL(date, true);
|
|
||||||
}
|
|
||||||
item.dateAdded = date;
|
|
||||||
|
|
||||||
if (!item.dateModified) {
|
|
||||||
items.dateModified = date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item.dateModified) {
|
|
||||||
// When there's no reliable modification date, we can assume that item doesn't get updated
|
|
||||||
Zotero.debug("FeedReader: Feed item missing a modification date (" + item.guid + ")");
|
|
||||||
} else {
|
|
||||||
// Convert date modified to string, since those are directly comparable
|
|
||||||
item.dateModified = Zotero.Date.dateToSQL(item.dateModified, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item.dateAdded && item.dateModified) {
|
|
||||||
// Use lastModified date
|
|
||||||
item.dateAdded = item.dateModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feedEntry.rights) item.rights = Zotero.FeedReader._getRichText(feedEntry.rights, 'rights');
|
if (feedEntry.rights) item.rights = Zotero.FeedReader._getRichText(feedEntry.rights, 'rights');
|
||||||
|
|
||||||
item.creators = Zotero.FeedReader._processCreators(feedEntry, 'authors', 'author');
|
item.creators = Zotero.FeedReader._processCreators(feedEntry, 'authors', 'author');
|
||||||
|
@ -429,8 +396,11 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
|
||||||
|
|
||||||
/** Done with basic metadata, now look for better data **/
|
/** Done with basic metadata, now look for better data **/
|
||||||
|
|
||||||
date = Zotero.FeedReader._getFeedField(feedEntry, 'publicationDate', 'prism')
|
let date = Zotero.FeedReader._getFeedField(feedEntry, 'publicationDate', 'prism')
|
||||||
|| Zotero.FeedReader._getFeedField(feedEntry, 'date', 'dc');
|
|| Zotero.FeedReader._getFeedField(feedEntry, 'date', 'dc')
|
||||||
|
|| Zotero.FeedReader._getFeedField(feedEntry, 'pubDate') // RSS
|
||||||
|
|| Zotero.FeedReader._getFeedField(feedEntry, 'published') // Atom
|
||||||
|
|| Zotero.FeedReader._getFeedField(feedEntry, 'updated'); // Atom
|
||||||
if (date) item.date = date;
|
if (date) item.date = date;
|
||||||
|
|
||||||
let publicationTitle = Zotero.FeedReader._getFeedField(feedEntry, 'publicationName', 'prism')
|
let publicationTitle = Zotero.FeedReader._getFeedField(feedEntry, 'publicationName', 'prism')
|
||||||
|
|
|
@ -98,7 +98,6 @@ Zotero.ItemTreeView.prototype.setTree = Zotero.Promise.coroutine(function* (tree
|
||||||
}
|
}
|
||||||
|
|
||||||
this._treebox = treebox;
|
this._treebox = treebox;
|
||||||
this.setSortColumn();
|
|
||||||
|
|
||||||
if (this._ownerDocument.defaultView.ZoteroPane_Local) {
|
if (this._ownerDocument.defaultView.ZoteroPane_Local) {
|
||||||
this._ownerDocument.defaultView.ZoteroPane_Local.setItemsPaneMessage(Zotero.getString('pane.items.loading'));
|
this._ownerDocument.defaultView.ZoteroPane_Local.setItemsPaneMessage(Zotero.getString('pane.items.loading'));
|
||||||
|
@ -260,48 +259,6 @@ Zotero.ItemTreeView.prototype.setTree = Zotero.Promise.coroutine(function* (tree
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
Zotero.ItemTreeView.prototype.setSortColumn = function() {
|
|
||||||
var dir, col, currentCol, currentDir;
|
|
||||||
|
|
||||||
for (let i=0, len=this._treebox.columns.count; i<len; i++) {
|
|
||||||
let column = this._treebox.columns.getColumnAt(i);
|
|
||||||
if (column.element.getAttribute('sortActive')) {
|
|
||||||
currentCol = column;
|
|
||||||
currentDir = column.element.getAttribute('sortDirection');
|
|
||||||
column.element.removeAttribute('sortActive');
|
|
||||||
column.element.removeAttribute('sortDirection');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let colId = Zotero.Prefs.get('itemTree.sortColumnId');
|
|
||||||
// Restore previous sort setting (feed -> 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
|
* Reload the rows from the data access methods
|
||||||
* (doesn't call the tree.invalidate methods, etc.)
|
* (doesn't call the tree.invalidate methods, etc.)
|
||||||
|
@ -2130,9 +2087,12 @@ Zotero.ItemTreeView.prototype.getSortedItems = function(asIDs) {
|
||||||
|
|
||||||
|
|
||||||
Zotero.ItemTreeView.prototype.getSortField = function() {
|
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) {
|
if (!column) {
|
||||||
column = this._treebox.columns.getFirstColumn()
|
column = this._treebox.columns.getFirstColumn();
|
||||||
}
|
}
|
||||||
// zotero-items-column-_________
|
// zotero-items-column-_________
|
||||||
return column.id.substring(20);
|
return column.id.substring(20);
|
||||||
|
@ -2176,6 +2136,9 @@ Zotero.ItemTreeView.prototype.getSortFields = function () {
|
||||||
* Returns 'ascending' or 'descending'
|
* Returns 'ascending' or 'descending'
|
||||||
*/
|
*/
|
||||||
Zotero.ItemTreeView.prototype.getSortDirection = function() {
|
Zotero.ItemTreeView.prototype.getSortDirection = function() {
|
||||||
|
if (this.collectionTreeRow.isFeed) {
|
||||||
|
return Zotero.Prefs.get('feedSortAsc') ? 'asc' : 'desc';
|
||||||
|
}
|
||||||
var column = this._treebox.columns.getSortedColumn();
|
var column = this._treebox.columns.getSortedColumn();
|
||||||
if (!column) {
|
if (!column) {
|
||||||
return 'ascending';
|
return 'ascending';
|
||||||
|
|
|
@ -2188,9 +2188,6 @@ Zotero.Schema = new function(){
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE tagsOld");
|
yield Zotero.DB.queryAsync("DROP TABLE tagsOld");
|
||||||
yield Zotero.DB.queryAsync("DROP TABLE librariesOld");
|
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) {
|
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, 98, NULL, 8)");
|
||||||
yield Zotero.DB.queryAsync("INSERT INTO itemTypeFields VALUES (17, 42, NULL, 9)");
|
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);
|
yield _updateDBVersion('userdata', toVersion);
|
||||||
|
|
|
@ -1376,7 +1376,9 @@ var ZoteroPane = new function()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isFeedItem) {
|
if (item.isFeedItem) {
|
||||||
item.translate();
|
if (! item.isTranslated) {
|
||||||
|
item.translate();
|
||||||
|
}
|
||||||
this.startItemReadTimeout(item.id);
|
this.startItemReadTimeout(item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ pref("extensions.zotero.lastLongTagMode", 0);
|
||||||
pref("extensions.zotero.lastLongTagDelimiter", ";");
|
pref("extensions.zotero.lastLongTagDelimiter", ";");
|
||||||
|
|
||||||
pref("extensions.zotero.fallbackSort", 'firstCreator,date,title,dateAdded');
|
pref("extensions.zotero.fallbackSort", 'firstCreator,date,title,dateAdded');
|
||||||
|
pref("extensions.zotero.feedSortAsc", false);
|
||||||
pref("extensions.zotero.sortCreatorAsString", false);
|
pref("extensions.zotero.sortCreatorAsString", false);
|
||||||
|
|
||||||
//Tag Cloud
|
//Tag Cloud
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- 82
|
-- 83
|
||||||
|
|
||||||
-- Copyright (c) 2009 Center for History and New Media
|
-- Copyright (c) 2009 Center for History and New Media
|
||||||
-- George Mason University, Fairfax, Virginia, USA
|
-- George Mason University, Fairfax, Virginia, USA
|
||||||
|
@ -203,6 +203,7 @@ CREATE TABLE feeds (
|
||||||
lastUpdate TIMESTAMP,
|
lastUpdate TIMESTAMP,
|
||||||
lastCheck TIMESTAMP,
|
lastCheck TIMESTAMP,
|
||||||
lastCheckError TEXT,
|
lastCheckError TEXT,
|
||||||
|
lastGUID TEXT,
|
||||||
cleanupAfter INT,
|
cleanupAfter INT,
|
||||||
refreshInterval INT,
|
refreshInterval INT,
|
||||||
FOREIGN KEY (libraryID) REFERENCES libraries(libraryID) ON DELETE CASCADE
|
FOREIGN KEY (libraryID) REFERENCES libraries(libraryID) ON DELETE CASCADE
|
||||||
|
@ -212,6 +213,7 @@ CREATE TABLE feedItems (
|
||||||
itemID INTEGER PRIMARY KEY,
|
itemID INTEGER PRIMARY KEY,
|
||||||
guid TEXT NOT NULL UNIQUE,
|
guid TEXT NOT NULL UNIQUE,
|
||||||
readTime TIMESTAMP,
|
readTime TIMESTAMP,
|
||||||
|
translatedTime TIMESTAMP,
|
||||||
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE
|
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,6 @@
|
||||||
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
|
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
|
||||||
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
|
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<description>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.</description>
|
|
||||||
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
|
|
||||||
<guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<title>The Engine That Does More</title>
|
<title>The Engine That Does More</title>
|
||||||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
|
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
|
||||||
|
|
|
@ -13,17 +13,17 @@
|
||||||
<managingEditor>editor@example.com</managingEditor>
|
<managingEditor>editor@example.com</managingEditor>
|
||||||
<webMaster>webmaster@example.com</webMaster>
|
<webMaster>webmaster@example.com</webMaster>
|
||||||
<item>
|
<item>
|
||||||
<title>Star City</title>
|
<description>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.</description>
|
||||||
|
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
|
||||||
|
<guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Star City (Updated)</title>
|
||||||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
|
<link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
|
||||||
<description>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>.</description>
|
<description>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>.</description>
|
||||||
<pubDate>Tue, 03 Jun 2037 09:39:21 GMT</pubDate>
|
<pubDate>Tue, 03 Jun 2037 09:39:21 GMT</pubDate>
|
||||||
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
|
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<description>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.</description>
|
|
||||||
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
|
|
||||||
<guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<title>The Engine That Does More</title>
|
<title>The Engine That Does More</title>
|
||||||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
|
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
|
||||||
|
|
|
@ -111,14 +111,13 @@ describe("Zotero.FeedReader", function () {
|
||||||
title: 'Star City',
|
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.',
|
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',
|
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: [{
|
creators: [{
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: 'editor@example.com',
|
lastName: 'editor@example.com',
|
||||||
creatorType: 'author',
|
creatorType: 'author',
|
||||||
fieldMode: 1
|
fieldMode: 1
|
||||||
}],
|
}],
|
||||||
|
date: 'Tue, 03 Jun 2003 09:39:21 GMT',
|
||||||
language: 'en-us',
|
language: 'en-us',
|
||||||
itemType: 'journalArticle'
|
itemType: 'journalArticle'
|
||||||
};
|
};
|
||||||
|
@ -136,8 +135,6 @@ describe("Zotero.FeedReader", function () {
|
||||||
title: 'Title 1',
|
title: 'Title 1',
|
||||||
abstractNote: 'Description 1',
|
abstractNote: 'Description 1',
|
||||||
url: 'http://www.example.com/item1',
|
url: 'http://www.example.com/item1',
|
||||||
dateModified: '2016-01-07 00:00:00',
|
|
||||||
dateAdded: '2016-01-07 00:00:00',
|
|
||||||
creators: [
|
creators: [
|
||||||
{ firstName: 'Author1 A. T.', lastName: 'Rohtua', creatorType: 'author' },
|
{ firstName: 'Author1 A. T.', lastName: 'Rohtua', creatorType: 'author' },
|
||||||
{ firstName: 'Author2 A.', lastName: 'Auth', creatorType: 'author' },
|
{ firstName: 'Author2 A.', lastName: 'Auth', creatorType: 'author' },
|
||||||
|
|
|
@ -206,9 +206,16 @@ describe("Zotero.Feed", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#updateFeed()', function() {
|
describe('#updateFeed()', function() {
|
||||||
|
var feed;
|
||||||
var feedUrl = getTestDataItemUrl("feed.rss");
|
var feedUrl = getTestDataItemUrl("feed.rss");
|
||||||
var modifiedFeedUrl = getTestDataItemUrl("feedModified.rss");
|
var modifiedFeedUrl = getTestDataItemUrl("feedModified.rss");
|
||||||
|
|
||||||
|
beforeEach(function* (){
|
||||||
|
feed = yield createFeed();
|
||||||
|
feed._feedUrl = feedUrl;
|
||||||
|
yield feed.updateFeed();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(function* () {
|
afterEach(function* () {
|
||||||
yield clearFeeds();
|
yield clearFeeds();
|
||||||
});
|
});
|
||||||
|
@ -225,15 +232,11 @@ describe("Zotero.Feed", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add new feed items', 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);
|
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();
|
let feed = yield createFeed();
|
||||||
feed._feedUrl = feedUrl;
|
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.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.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* () {
|
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);
|
let feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
|
||||||
feedItem.isRead = true;
|
feedItem.isRead = true;
|
||||||
yield feedItem.forceSaveTx();
|
yield feedItem.forceSaveTx();
|
||||||
feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
|
feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
|
||||||
assert.isTrue(feedItem.isRead);
|
assert.isTrue(feedItem.isRead);
|
||||||
|
|
||||||
let oldDateModified = feedItem.dateModified;
|
let oldDateModified = feedItem.getField('date');
|
||||||
|
|
||||||
feed._feedUrl = modifiedFeedUrl;
|
feed._feedUrl = modifiedFeedUrl;
|
||||||
yield feed.updateFeed();
|
yield feed.updateFeed();
|
||||||
|
|
||||||
feedItem = yield Zotero.FeedItems.getAsyncByGUID("http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
|
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)
|
assert.isFalse(feedItem.isRead)
|
||||||
});
|
});
|
||||||
it('should skip items that are not modified', function* () {
|
it('should skip items that are not modified', function* () {
|
||||||
let feed = yield createFeed();
|
let save = sinon.spy(Zotero.FeedItem.prototype, 'save');
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
feed._feedUrl = modifiedFeedUrl;
|
feed._feedUrl = modifiedFeedUrl;
|
||||||
yield feed.updateFeed();
|
yield feed.updateFeed();
|
||||||
|
|
||||||
feedItems = yield Zotero.FeedItems.getAll(feed.id);
|
assert.equal(save.thisValues[0].guid, "http://liftoff.msfc.nasa.gov/2003/06/03.html#item573:"+feed.id);
|
||||||
|
save.restore();
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
it('should update unread count', function* () {
|
it('should update unread count', function* () {
|
||||||
let feed = yield createFeed();
|
assert.equal(feed.unreadCount, 3);
|
||||||
feed._feedUrl = feedUrl;
|
|
||||||
yield feed.updateFeed();
|
|
||||||
|
|
||||||
assert.equal(feed.unreadCount, 4);
|
|
||||||
|
|
||||||
let feedItems = yield Zotero.FeedItems.getAll(feed.id);
|
let feedItems = yield Zotero.FeedItems.getAll(feed.id);
|
||||||
for (let feedItem of feedItems) {
|
for (let feedItem of feedItems) {
|
||||||
|
@ -309,7 +287,22 @@ describe("Zotero.Feed", function() {
|
||||||
feed._feedUrl = modifiedFeedUrl;
|
feed._feedUrl = modifiedFeedUrl;
|
||||||
yield feed.updateFeed();
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue