From 9686758c7d9a70fc94e3a215ea82430a4d74b580 Mon Sep 17 00:00:00 2001 From: Aurimas Vinckevicius Date: Thu, 6 Nov 2014 22:10:59 -0600 Subject: [PATCH] Add feeds to collections tree view and items tree view --- .../content/zotero/xpcom/collectionTreeRow.js | 19 ++- .../zotero/xpcom/collectionTreeView.js | 75 +++++++++--- chrome/content/zotero/xpcom/itemTreeView.js | 3 + chrome/content/zotero/zoteroPane.js | 109 ++++++++++++++++++ chrome/content/zotero/zoteroPane.xul | 3 + chrome/locale/en-US/zotero/zotero.dtd | 2 + chrome/locale/en-US/zotero/zotero.properties | 12 +- chrome/skin/default/zotero/overlay.css | 12 +- .../skin/default/zotero/toolbar-feed-edit.png | Bin 0 -> 801 bytes .../skin/default/zotero/treesource-feed.png | Bin 0 -> 691 bytes .../default/zotero/treesource-feedLibrary.png | Bin 0 -> 3359 bytes 11 files changed, 215 insertions(+), 20 deletions(-) create mode 100644 chrome/skin/default/zotero/toolbar-feed-edit.png create mode 100644 chrome/skin/default/zotero/treesource-feed.png create mode 100644 chrome/skin/default/zotero/treesource-feedLibrary.png diff --git a/chrome/content/zotero/xpcom/collectionTreeRow.js b/chrome/content/zotero/xpcom/collectionTreeRow.js index f54a09045..80b192851 100644 --- 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 index bfeb9cda6..0a3df01cf 100644 --- 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 index 1e47a1842..5b9d3e969 100644 --- 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 index c4468160c..a2c29b67e 100644 --- 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 { + 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 index 42d68c9aa..2234a8c0e 100644 --- a/chrome/content/zotero/zoteroPane.xul +++ b/chrome/content/zotero/zoteroPane.xul @@ -241,10 +241,13 @@ + + + diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd index ed62b60b4..44ce77703 100644 --- a/chrome/locale/en-US/zotero/zotero.dtd +++ b/chrome/locale/en-US/zotero/zotero.dtd @@ -105,6 +105,8 @@ + + diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index e0c65673f..b1ab2206c 100644 --- 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 index feefb5314..fd6dd68f6 100644 --- 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 new file mode 100644 index 0000000000000000000000000000000000000000..f1fde7a9ceeb500d97e5618ee9c0deb9d38519fc GIT binary patch literal 801 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 p((C&MmSkdygSWwE