commit ac440b2b38b49eab254b9bcd40cc6ddfc9339282
parent 1d45c6c88258e8b08d43b3c853032d1b00307d30
Author: Dan Stillman <dstillman@zotero.org>
Date: Tue, 9 Jun 2015 01:29:26 -0400
Don't reload collections list when sources are modified
Just update the row that changed, moving it if necessary.
Diffstat:
4 files changed, 129 insertions(+), 67 deletions(-)
diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js
@@ -287,20 +287,30 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
return;
}
- if (action == 'refresh' && type == 'trash') {
- // libraryID is passed as parameter to 'refresh'
- let deleted = yield Zotero.Items.getDeleted(ids[0], true);
- this._trashNotEmpty[ids[0]] = !!deleted.length;
- return;
- }
-
+ //
+ // Actions that don't change the selection
+ //
if (action == 'redraw') {
this._treebox.invalidate();
return;
}
+ if (action == 'refresh') {
+ // If trash is refreshed, we probably need to update the icon from full to empty
+ if (type == 'trash') {
+ // libraryID is passed as parameter to 'refresh'
+ let deleted = yield Zotero.Items.getDeleted(ids[0], true);
+ this._trashNotEmpty[ids[0]] = !!deleted.length;
+ let row = this.getRowIndexByID("T" + ids[0]);
+ this._treebox.invalidateRow(row);
+ }
+ return;
+ }
+ //
+ // Actions that can change the selection
+ //
+ var currentTreeRow = this.getRow(this.selection.currentIndex);
this.selection.selectEventsSuppressed = true;
- var savedSelection = this.saveSelection();
if (action == 'delete') {
var selectedIndex = this.selection.count ? this.selection.currentIndex : 0;
@@ -356,25 +366,45 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
else if(action == 'move')
{
yield this.reload();
+ yield this.restoreSelection(currentTreeRow);
+ }
+ else if (action == 'modify') {
+ let row;
+ let id = ids[0];
- // Open the new parent collection if closed
- for (var i=0; i<ids.length; i++) {
- var collection = yield Zotero.Collections.getAsync(ids[i]);
- var parentID = collection.parentID;
- if (parentID && this._rowMap["C" + parentID] &&
- !this.isContainerOpen(this._rowMap["C" + parentID])) {
- yield this.toggleOpenState(this._rowMap["C" + parentID]);
+ switch (type) {
+ case 'collection':
+ row = this.getRowIndexByID("C" + id);
+ if (row !== false) {
+ // TODO: Only move if name changed
+ let reopen = this.isContainerOpen(row);
+ if (reopen) {
+ this._closeContainer(row);
+ }
+ this._removeRow(row);
+ yield this._addSortedRow('collection', id);
+ if (reopen) {
+ yield this.toggleOpenState(row);
+ }
+ yield this.restoreSelection(currentTreeRow);
}
- }
+ break;
- this.rememberSelection(savedSelection);
- }
- else if (action == 'modify' || action == 'refresh') {
- if (type != 'bucket'
- && (type != 'publications' || this.selectedTreeRow.isPublications())) {
+ case 'search':
+ row = this.getRowIndexByID("S" + id);
+ if (row !== false) {
+ // TODO: Only move if name changed
+ this._removeRow(row);
+ yield this._addSortedRow('search', id);
+ yield this.restoreSelection(currentTreeRow);
+ }
+ break;
+
+ default:
yield this.reload();
+ yield this.restoreSelection(currentTreeRow);
+ break;
}
- this.rememberSelection(savedSelection);
}
else if(action == 'add')
{
@@ -388,11 +418,6 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
case 'search':
yield this._addSortedRow(type, id);
- if (Zotero.suppressUIUpdates) {
- this.rememberSelection(savedSelection);
- break;
- }
-
if (selectRow) {
if (type == 'collection') {
yield this.selectCollection(id);
@@ -407,7 +432,8 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
case 'group':
yield this.reload();
// Groups can only be created during sync
- this.rememberSelection(savedSelection);
+ let libraryID = Zotero.Groups.getLibraryIDFromGroupID(id);
+ yield this.selectByID("L" + libraryID);
break;
}
}
@@ -422,6 +448,10 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
* Add a row in the appropriate place
*
* This only adds a row if it would be visible without opening any containers
+ *
+ * @param {String} objectType
+ * @param {Integer} id
+ * @return {Integer|false} - Index at which the row was added, or false if it wasn't added
*/
Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(function* (objectType, id) {
let beforeRow;
@@ -456,6 +486,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
else {
// Get all collections at the same level that don't have a different parent
startRow++;
+ loop:
for (let i = startRow; i < this.rowCount; i++) {
let treeRow = this.getRow(i);
beforeRow = i;
@@ -474,8 +505,8 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
// Fast forward through subcollections
while (rowLevel > level) {
beforeRow = ++i;
- if (i == this.rowCount) {
- break;
+ if (i == this.rowCount || !this.getRow(i).isCollection()) {
+ break loop;
}
treeRow = this.getRow(i);
rowLevel = this.getLevel(i);
@@ -533,7 +564,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
beforeRow
);
}
- return true;
+ return beforeRow;
});
@@ -763,7 +794,7 @@ Zotero.CollectionTreeView.prototype.setCellText = function (row, col, val) {
}
var treeRow = this.getRow(row);
treeRow.ref.name = val;
- treeRow.ref.save();
+ treeRow.ref.saveTx();
}
@@ -877,6 +908,13 @@ Zotero.CollectionTreeView.prototype.selectByID = Zotero.Promise.coroutine(functi
});
+Zotero.CollectionTreeView.prototype.restoreSelection = Zotero.Promise.coroutine(function* (collectionTreeRow) {
+ yield this.selectByID(collectionTreeRow.id);
+ // Swap back in the previous tree row to avoid reselection and subsequent items view refresh
+ this._rows[this.selection.currentIndex] = collectionTreeRow;
+})
+
+
/**
* @param {Integer} libraryID Library to select
*/
@@ -1172,37 +1210,6 @@ Zotero.CollectionTreeView.prototype.getSelectedCollection = function(asID) {
}
-/*
- * Saves the ids of the currently selected item for later
- */
-Zotero.CollectionTreeView.prototype.saveSelection = function()
-{
- for (var i=0, len=this.rowCount; i<len; i++) {
- if (this.selection.isSelected(i)) {
- var treeRow = this.getRow(i);
- var id = treeRow.id;
- if (id) {
- return id;
- }
- else {
- break;
- }
- }
- }
- return false;
-}
-
-/*
- * Sets the selection based on saved selection ids (see above)
- */
-Zotero.CollectionTreeView.prototype.rememberSelection = Zotero.Promise.coroutine(function* (selection)
-{
- if (selection && this._rowMap[selection] != 'undefined') {
- this.selection.select(this._rowMap[selection]);
- }
-});
-
-
/**
* Creates mapping of item group ids to tree rows
*/
diff --git a/chrome/content/zotero/xpcom/libraryTreeView.js b/chrome/content/zotero/xpcom/libraryTreeView.js
@@ -138,7 +138,7 @@ Zotero.LibraryTreeView.prototype = {
var lastRow = row == this.rowCount - 1;
if (lastRow && this.selection.isSelected(row)) {
- // Deslect removed row
+ // Deselect removed row
this.selection.toggleSelect(row);
// If no other rows selected, select row before
if (this.selection.count == 0 && row !== 0) {
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
@@ -1282,6 +1282,10 @@ var ZoteroPane = new function()
}
var collectionTreeRow = this.getCollectionTreeRow();
+ // I don't think this happens in normal usage, but it can happen during tests
+ if (!collectionTreeRow) {
+ return false;
+ }
// Single item selected
if (this.itemsView.selection.count == 1 && this.itemsView.selection.currentIndex != -1)
diff --git a/test/tests/collectionTreeViewTest.js b/test/tests/collectionTreeViewTest.js
@@ -1,11 +1,12 @@
"use strict";
describe("Zotero.CollectionTreeView", function() {
- var win, cv;
+ var win, zp, cv;
before(function* () {
win = yield loadZoteroPane();
- cv = win.ZoteroPane.collectionsView;
+ zp = win.ZoteroPane;
+ cv = zp.collectionsView;
});
beforeEach(function () {
// TODO: Add a selectCollection() function and select a collection instead?
@@ -137,7 +138,7 @@ describe("Zotero.CollectionTreeView", function() {
assert.equal(cv.getSelectedLibraryID(), Zotero.Libraries.userLibraryID);
});
- it("should reselect a selected modified collection", function* () {
+ it("should maintain selection on a selected modified collection", function* () {
// Create collection
var collection = new Zotero.Collection;
collection.name = "Reselect on modify";
@@ -154,6 +155,56 @@ describe("Zotero.CollectionTreeView", function() {
assert.equal(selected, id);
});
+ it("should re-sort a modified collection", function* () {
+ var prefix = Zotero.Utilities.randomString() + " ";
+ var collectionA = yield createDataObject('collection', { name: prefix + "A" });
+ var collectionB = yield createDataObject('collection', { name: prefix + "B" });
+
+ var aRow = cv.getRowIndexByID("C" + collectionA.id);
+ var aRowOriginal = aRow;
+ var bRow = cv.getRowIndexByID("C" + collectionB.id);
+ assert.equal(bRow, aRow + 1);
+
+ collectionA.name = prefix + "C";
+ yield collectionA.saveTx();
+
+ var aRow = cv.getRowIndexByID("C" + collectionA.id);
+ var bRow = cv.getRowIndexByID("C" + collectionB.id);
+ assert.equal(bRow, aRowOriginal);
+ assert.equal(aRow, bRow + 1);
+ })
+
+ it("should re-sort a modified search", function* () {
+ var prefix = Zotero.Utilities.randomString() + " ";
+ var searchA = yield createDataObject('search', { name: prefix + "A" });
+ var searchB = yield createDataObject('search', { name: prefix + "B" });
+
+ var aRow = cv.getRowIndexByID("S" + searchA.id);
+ var aRowOriginal = aRow;
+ var bRow = cv.getRowIndexByID("S" + searchB.id);
+ assert.equal(bRow, aRow + 1);
+
+ searchA.name = prefix + "C";
+ yield searchA.saveTx();
+
+ var aRow = cv.getRowIndexByID("S" + searchA.id);
+ var bRow = cv.getRowIndexByID("S" + searchB.id);
+ assert.equal(bRow, aRowOriginal);
+ assert.equal(aRow, bRow + 1);
+ })
+
+ it("shouldn't refresh the items list when a collection is modified", function* () {
+ var collection = yield createDataObject('collection');
+ yield waitForItemsLoad(win);
+ var itemsView = zp.itemsView;
+
+ collection.name = "New Name";
+ yield collection.saveTx();
+
+ yield waitForItemsLoad(win);
+ assert.equal(zp.itemsView, itemsView);
+ })
+
it("should add a saved search after collections", function* () {
var collection = new Zotero.Collection;
collection.name = "Test";