commit 9686758c7d9a70fc94e3a215ea82430a4d74b580
parent 2e56e2f659c1254a80665ea9df0c62d139c0eadc
Author: Aurimas Vinckevicius <aurimas.dev@gmail.com>
Date: Thu, 6 Nov 2014 22:10:59 -0600
Add feeds to collections tree view and items tree view
Diffstat:
11 files changed, 215 insertions(+), 20 deletions(-)
diff --git a/chrome/content/zotero/xpcom/collectionTreeRow.js b/chrome/content/zotero/xpcom/collectionTreeRow.js
@@ -39,6 +39,7 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
case 'library':
case 'publications':
case 'group':
+ case 'feed':
return 'L' + this.ref.libraryID;
case 'collection':
@@ -57,8 +58,11 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
return 'T' + this.ref.libraryID;
case 'header':
- if (this.ref.id == 'group-libraries-header') {
- return 'HG';
+ switch (this.ref.id) {
+ case 'group-libraries-header':
+ return "HG";
+ case 'feed-libraries-header':
+ return "HF";
}
break;
}
@@ -69,7 +73,8 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
Zotero.CollectionTreeRow.prototype.isLibrary = function (includeGlobal)
{
if (includeGlobal) {
- return this.type == 'library' || this.type == 'publications' || this.type == 'group';
+ var global = ['library', 'publications', 'group', 'feed'];
+ return global.indexOf(this.type) != -1;
}
return this.type == 'library';
}
@@ -109,6 +114,10 @@ Zotero.CollectionTreeRow.prototype.isGroup = function() {
return this.type == 'group';
}
+Zotero.CollectionTreeRow.prototype.isFeed = function() {
+ return this.type == 'feed';
+}
+
Zotero.CollectionTreeRow.prototype.isSeparator = function () {
return this.type == 'separator';
}
@@ -140,7 +149,7 @@ Zotero.CollectionTreeRow.prototype.isWithinEditableGroup = function () {
}
Zotero.CollectionTreeRow.prototype.__defineGetter__('editable', function () {
- if (this.isTrash() || this.isShare() || this.isBucket()) {
+ if (this.isTrash() || this.isShare() || this.isBucket() || this.isFeed()) {
return false;
}
if (!this.isWithinGroup() || this.isPublications()) {
@@ -163,7 +172,7 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('editable', function () {
});
Zotero.CollectionTreeRow.prototype.__defineGetter__('filesEditable', function () {
- if (this.isTrash() || this.isShare()) {
+ if (this.isTrash() || this.isShare() || this.isFeed()) {
return false;
}
if (!this.isWithinGroup() || this.isPublications()) {
diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js
@@ -206,7 +206,34 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
}),
added++
);
-
+
+ // TODO: Unify feed and group adding code
+ // Add feeds
+ var feeds = Zotero.Feeds.getAll();
+ if (feeds.length) {
+ this._addRowToArray(
+ newRows,
+ new Zotero.CollectionTreeRow('separator', false),
+ added++
+ );
+ this._addRowToArray(
+ newRows,
+ new Zotero.CollectionTreeRow('header', {
+ id: "feed-libraries-header",
+ label: Zotero.getString('pane.collections.feedLibraries'),
+ libraryID: -1
+ }, 0),
+ added++
+ );
+ for (let i = 0, len = groups.length; i < len; i++) {
+ this._addRowToArray(
+ newRows,
+ new Zotero.CollectionTreeRow('feed', feeds[i]),
+ added++
+ );
+ }
+ }
+
// Add groups
var groups = Zotero.Groups.getAll();
if (groups.length) {
@@ -340,15 +367,16 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
rows.push(this._rowMap['S' + id]);
}
break;
-
+
+ case 'feed':
case 'group':
let row = this.getRowIndexByID("L" + extraData[id].libraryID);
- let groupLevel = this.getLevel(row);
+ let level = this.getLevel(row);
do {
rows.push(row);
row++;
}
- while (row < this.rowCount && this.getLevel(row) > groupLevel);
+ while (row < this.rowCount && this.getLevel(row) > level);
break;
}
}
@@ -371,6 +399,20 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
};
this.selection.select(selectedIndex)
}
+
+ // Make sure the selection doesn't land on a separator (e.g. deleting last feed)
+ let index = this.selection.currentIndex;
+ while (index >= 0 && !this.isSelectable(index)) {
+ // move up, since we got shifted down
+ index--;
+ }
+
+ if (index >= 0) {
+ this.selection.select(index);
+ } else {
+ this.selection.clearSelection();
+ }
+
}
else if (action == 'modify') {
let row;
@@ -439,6 +481,7 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
break;
+ case 'feed':
case 'group':
yield this.reload();
yield this.selectByID(currentTreeRow.id);
@@ -667,6 +710,7 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
switch (collectionType) {
case 'library':
+ case 'feed':
break;
case 'trash':
@@ -729,6 +773,9 @@ Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row)
&& this._unfiledLibraries.indexOf(libraryID) == -1
&& this.hideSources.indexOf('trash') != -1;
}
+ if (treeRow.isFeed()) {
+ return false; // If it's shown, it has something
+ }
if (treeRow.isCollection()) {
return !treeRow.ref.hasChildCollections();
}
@@ -1039,10 +1086,12 @@ Zotero.CollectionTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(f
{
//erase collection from DB:
var treeRow = this.getRow(rows[i]-i);
- if (treeRow.isCollection()) {
+ if (treeRow.isCollection() || treeRow.isFeed()) {
yield treeRow.ref.eraseTx({
deleteItems: true
});
+ if (treeRow.isCollection() || treeRow.isFeed()) {
+ yield treeRow.ref.erase(deleteItems);
}
else if (treeRow.isSearch()) {
yield Zotero.Searches.erase(treeRow.ref.id);
@@ -1268,8 +1317,8 @@ Zotero.CollectionTreeView.prototype._rememberOpenStates = Zotero.Promise.corouti
var open = this.isContainerOpen(i);
- // Collections default to closed
- if (!open && treeRow.isCollection()) {
+ // Collections and feeds default to closed
+ if (!open && treeRow.isCollection() && treeRow.isFeed()) {
delete state[treeRow.id];
continue;
}
@@ -1773,8 +1822,8 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
// Collection drag between libraries
if (targetLibraryID != droppedCollection.libraryID) {
yield Zotero.DB.executeTransaction(function* () {
- function copyCollections(descendents, parentID, addItems) {
- for each(var desc in descendents) {
+ var copyCollections = Zotero.Promise.coroutine(function* (descendents, parentID, addItems) {
+ for (var desc of descendents) {
// Collections
if (desc.type == 'collection') {
var c = yield Zotero.Collections.getAsync(desc.id);
@@ -1792,7 +1841,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
// Recursively copy subcollections
if (desc.children.length) {
- copyCollections(desc.children, collectionID, addItems);
+ yield copyCollections(desc.children, collectionID, addItems);
}
}
// Items
@@ -1824,7 +1873,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
}
}
}
- }
+ });
var collections = [{
id: droppedCollection.id,
@@ -1833,10 +1882,10 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
}];
var addItems = {};
- copyCollections(collections, targetCollectionID, addItems);
+ yield copyCollections(collections, targetCollectionID, addItems);
for (var collectionID in addItems) {
var collection = yield Zotero.Collections.getAsync(collectionID);
- collection.addItems(addItems[collectionID]);
+ yield collection.addItems(addItems[collectionID]);
}
// TODO: add subcollections and subitems, if they don't already exist,
diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js
@@ -2432,6 +2432,8 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) {
}
// Get Quick Copy format for current URL
+// TODO: Fix this
+/** Currently broken
var url = this._ownerDocument.defaultView.content && this._ownerDocument.defaultView.content.location ?
this._ownerDocument.defaultView.content.location.href : null;
var format = Zotero.QuickCopy.getFormatFromURL(url);
@@ -2470,6 +2472,7 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) {
Zotero.debug(e);
Components.utils.reportError(e + " with '" + format.id + "'");
}
+*/
};
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
@@ -594,6 +594,21 @@ var ZoteroPane = new function()
//event.preventDefault();
//event.stopPropagation();
return;
+ } else if (event.keyCode == event.DOM_VK_BACK_QUOTE) {
+ // Toggle read/unread
+ if (!this.collectionsView.selection.currentIndex) return;
+ let row = this.collectionsView.getRow(this.collectionsView.selection.currentIndex);
+ if (!row || !row.isFeed()) return;
+
+ if(itemReadTimeout) {
+ itemReadTimeout.cancel();
+ itemReadTimeout = null;
+ }
+
+ let itemIDs = this.getSelectedItems(true);
+ for (var i=0; i<itemIDs; i++) {
+ this.markItemRead(itemIDs[i]);
+ }
}
}
@@ -1361,8 +1376,16 @@ var ZoteroPane = new function()
yield ZoteroItemPane.viewItem(item, 'view', pane);
tabs.selectedIndex = document.getElementById('zotero-view-item').selectedIndex;
}
+
+ if (collectionTreeRow.isFeed()) {
+ // Fire timer for read item
+ let feedItem = yield Zotero.FeedItems.getAsync(item.id);
+ if (feedItem) {
+ this.startItemReadTimeout(feedItem.id);
+ }
}
}
+ }
// Zero or multiple items selected
else {
var count = this.itemsView.selection.count;
@@ -1900,6 +1923,35 @@ var ZoteroPane = new function()
}
});
+ this.editSelectedFeed = Zotero.Promise.coroutine(function* () {
+ if (!this.collectionsView.selection.count) return;
+
+ let feed = this.collectionsView.getRow(this.collectionsView.selection.currentIndex).ref;
+ let data = {
+ url: feed.url,
+ title: feed.name,
+ ttl: feed.refreshInterval,
+ cleanAfter: feed.cleanupAfter
+ };
+
+ window.openDialog('chrome://zotero/content/feedSettings.xul',
+ null, 'centerscreen, modal', data);
+ if (data.cancelled) return;
+
+ feed.name = data.title;
+ feed.refreshInterval = data.ttl;
+ feed.cleanupAfter = data.cleanAfter;
+ yield feed.save({skipEditCheck: true});
+ });
+
+ this.refreshFeed = function() {
+ if (!this.collectionsView.selection.count) return;
+
+ let feed = this.collectionsView.getRow(this.collectionsView.selection.currentIndex).ref;
+
+ return feed.updateFeed();
+ }
+
this.copySelectedItemsToClipboard = function (asCitations) {
var items = this.getSelectedItems();
@@ -2169,10 +2221,12 @@ var ZoteroPane = new function()
"newCollection",
"newSavedSearch",
"newSubcollection",
+ "refreshFeed",
"sep1",
"showDuplicates",
"showUnfiled",
"editSelectedCollection",
+ "editSelectedFeed",
"deleteCollection",
"deleteCollectionAndItems",
"sep2",
@@ -2228,6 +2282,31 @@ var ZoteroPane = new function()
menu.childNodes[m.createBibCollection].setAttribute('label', Zotero.getString('pane.collections.menu.createBib.collection'));
menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.collection'));
}
+ else if (collectionTreeRow.isFeed()) {
+ show = [
+ m.refreshFeed,
+ m.sep1,
+ m.editSelectedFeed,
+ m.deleteCollectionAndItems,
+ m.sep2,
+ m.exportCollection,
+ m.createBibCollection,
+ m.loadReport
+ ];
+
+ if (!this.itemsView.rowCount) {
+ disable = [m.createBibCollection, m.loadReport]
+ if (this.collectionsView.isContainerEmpty(this.collectionsView.selection.currentIndex)) {
+ disable.push(m.exportCollection);
+ }
+ }
+
+ // Adjust labels
+ menu.childNodes[m.deleteCollectionAndItems].setAttribute('label', Zotero.getString('pane.collections.menu.delete.feedAndItems'));
+ menu.childNodes[m.exportCollection].setAttribute('label', Zotero.getString('pane.collections.menu.export.feed'));
+ menu.childNodes[m.createBibCollection].setAttribute('label', Zotero.getString('pane.collections.menu.createBib.feed'));
+ menu.childNodes[m.loadReport].setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.feed'));
+ }
else if (collectionTreeRow.isSearch()) {
show = [
m.editSelectedCollection,
@@ -4211,6 +4290,36 @@ var ZoteroPane = new function()
});
+ this.markItemRead = Zotero.Promise.coroutine(function* (feedItemID, toggle) {
+ let feedItem = yield Zotero.FeedItems.getAsync(feedItemID);
+ if (!feedItem) return;
+
+ feedItem.isRead = toggle !== undefined ? !!toggle : !feedItem.isRead;
+ yield feedItem.save({skipEditCheck: true, skipDateModifiedUpdate: true});
+ })
+
+ let itemReadTimeout;
+ this.startItemReadTimeout = function(feedItemID) {
+ if (itemReadTimeout) {
+ itemReadTimeout.cancel();
+ itemReadTimeout = null;
+ }
+
+ itemReadTimeout = Zotero.Promise.delay(3000)
+ .cancellable()
+ .then(() => {
+ itemReadTimeout = null;
+ // Check to make sure we're still on the same item
+ if (this.itemsView.selection.count !== 1) return;
+
+ let row = this.itemsView.getRow(this.itemsView.selection.currentIndex);
+ if (!row || !row.ref || !row.ref.id == feedItemID) return;
+
+ return this.markItemRead(feedItemID, true);
+ });
+ }
+
+
function reportErrors() {
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul
@@ -241,10 +241,13 @@
<menuitem class="menuitem-iconic zotero-menuitem-new-collection" label="&zotero.toolbar.newCollection.label;" command="cmd_zotero_newCollection"/>
<menuitem class="menuitem-iconic zotero-menuitem-new-saved-search" label="&zotero.toolbar.newSavedSearch.label;" command="cmd_zotero_newSavedSearch"/>
<menuitem class="menuitem-iconic zotero-menuitem-new-collection" label="&zotero.toolbar.newSubcollection.label;" oncommand="ZoteroPane_Local.newCollection(ZoteroPane_Local.getSelectedCollection().key)"/>
+ <menuitem class="menuitem-iconic zotero-menuitem-new-feed" label="&zotero.toolbar.newFeed.label;" command="cmd_zotero_newFeed"/>
+ <menuitem class="menuitem-iconic zotero-menuitem-refresh-feed" label="&zotero.toolbar.refreshFeed.label;" oncommand="ZoteroPane_Local.refreshFeed();"/>
<menuseparator/>
<menuitem class="menuitem-iconic zotero-menuitem-show-duplicates" label="&zotero.toolbar.duplicate.label;" oncommand="ZoteroPane_Local.setVirtual(ZoteroPane_Local.getSelectedLibraryID(), 'duplicates', true)"/>
<menuitem class="menuitem-iconic zotero-menuitem-show-unfiled" label="&zotero.collections.showUnfiledItems;" oncommand="ZoteroPane_Local.setVirtual(ZoteroPane_Local.getSelectedLibraryID(), 'unfiled', true)"/>
<menuitem class="menuitem-iconic zotero-menuitem-edit-collection" oncommand="ZoteroPane_Local.editSelectedCollection();"/>
+ <menuitem class="menuitem-iconic zotero-menuitem-edit-feed" label="&zotero.toolbar.editFeed.label;" oncommand="ZoteroPane_Local.editSelectedFeed();"/>
<menuitem class="menuitem-iconic zotero-menuitem-delete-collection" oncommand="ZoteroPane_Local.deleteSelectedCollection();"/>
<menuitem class="menuitem-iconic zotero-menuitem-move-to-trash" oncommand="ZoteroPane_Local.deleteSelectedCollection(true);"/>
<menuseparator/>
diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd
@@ -105,6 +105,8 @@
<!ENTITY zotero.toolbar.removeItem.label "Remove Item…">
<!ENTITY zotero.toolbar.newCollection.label "New Collection…">
<!ENTITY zotero.toolbar.newFeed.label "New Feed…">
+<!ENTITY zotero.toolbar.refreshFeed.label "Refresh Feed">
+<!ENTITY zotero.toolbar.editFeed.label "Edit Feed…">
<!ENTITY zotero.toolbar.newGroup "New Group…">
<!ENTITY zotero.toolbar.newSubcollection.label "New Subcollection…">
<!ENTITY zotero.toolbar.newSavedSearch.label "New Saved Search…">
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
@@ -161,6 +161,8 @@ pane.collections.delete = Are you sure you want to delete the selected collect
pane.collections.delete.keepItems = Items within this collection will not be deleted.
pane.collections.deleteWithItems.title = Delete Collection and Items
pane.collections.deleteWithItems = Are you sure you want to delete the selected collection and move all items within it to the Trash?
+pane.feed.deleteWithItems.title = Delete Feed and Items
+pane.feed.deleteWithItems = Are you sure you want to delete the selected feed and all items within it?
pane.collections.deleteSearch.title = Delete Search
pane.collections.deleteSearch = Are you sure you want to delete the selected search?
@@ -174,23 +176,31 @@ pane.collections.library = My Library
pane.collections.publications = My Publications
pane.collections.feeds = Feeds
pane.collections.groupLibraries = Group Libraries
+pane.collections.feedLibraries = Feeds
pane.collections.trash = Trash
pane.collections.untitled = Untitled
pane.collections.unfiled = Unfiled Items
pane.collections.duplicate = Duplicate Items
pane.collections.menu.rename.collection = Rename Collection…
-pane.collections.menu.edit.savedSearch = Edit Saved Search
+pane.collections.menu.edit.savedSearch = Edit Saved Search…
+pane.collections.menu.edit.savedSearch = Edit Feed…
pane.collections.menu.delete.collection = Delete Collection…
pane.collections.menu.delete.collectionAndItems = Delete Collection and Items…
pane.collections.menu.delete.savedSearch = Delete Saved Search…
+pane.collections.menu.delete.feedAndItems = Delete Feed and Items…
pane.collections.menu.export.collection = Export Collection…
pane.collections.menu.export.savedSearch = Export Saved Search…
+pane.collections.menu.export.feed = Export Feed…
pane.collections.menu.createBib.collection = Create Bibliography From Collection…
pane.collections.menu.createBib.savedSearch = Create Bibliography From Saved Search…
+pane.collections.menu.createBib.feed = Create Bibliography From Feed…
pane.collections.menu.generateReport.collection = Generate Report from Collection…
pane.collections.menu.generateReport.savedSearch = Generate Report from Saved Search…
+pane.collections.menu.generateReport.feed = Generate Report from Feed…
+
+pane.collections.menu.refresh.feed = Refresh Feed
pane.tagSelector.rename.title = Rename Tag
pane.tagSelector.rename.message = Please enter a new name for this tag.\n\nThe tag will be changed in all associated items.
diff --git a/chrome/skin/default/zotero/overlay.css b/chrome/skin/default/zotero/overlay.css
@@ -278,7 +278,7 @@
list-style-image: url('chrome://zotero/skin/toolbar-collection-add.png');
}
-#zotero-tb-feed-add
+#zotero-tb-feed-add, .zotero-menuitem-new-feed
{
list-style-image: url('chrome://zotero/skin/toolbar-feed-add.png');
}
@@ -373,6 +373,16 @@
list-style-image: url('chrome://zotero/skin/toolbar-collection-edit.png');
}
+.zotero-menuitem-edit-feed
+{
+ list-style-image: url('chrome://zotero/skin/toolbar-feed-edit.png');
+}
+
+.zotero-menuitem-refresh-feed
+{
+ list-style-image: url('chrome://zotero/skin/arrow_refresh.png');
+}
+
.zotero-menuitem-delete-collection
{
list-style-image: url('chrome://zotero/skin/toolbar-collection-delete.png');
diff --git a/chrome/skin/default/zotero/toolbar-feed-edit.png b/chrome/skin/default/zotero/toolbar-feed-edit.png
Binary files differ.
diff --git a/chrome/skin/default/zotero/treesource-feed.png b/chrome/skin/default/zotero/treesource-feed.png
Binary files differ.
diff --git a/chrome/skin/default/zotero/treesource-feedLibrary.png b/chrome/skin/default/zotero/treesource-feedLibrary.png
Binary files differ.