Don't reload collections list when sources are modified
Just update the row that changed, moving it if necessary.
This commit is contained in:
parent
1d45c6c882
commit
ac440b2b38
|
@ -287,20 +287,30 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == 'refresh' && type == 'trash') {
|
//
|
||||||
// libraryID is passed as parameter to 'refresh'
|
// Actions that don't change the selection
|
||||||
let deleted = yield Zotero.Items.getDeleted(ids[0], true);
|
//
|
||||||
this._trashNotEmpty[ids[0]] = !!deleted.length;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action == 'redraw') {
|
if (action == 'redraw') {
|
||||||
this._treebox.invalidate();
|
this._treebox.invalidate();
|
||||||
return;
|
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;
|
this.selection.selectEventsSuppressed = true;
|
||||||
var savedSelection = this.saveSelection();
|
|
||||||
|
|
||||||
if (action == 'delete') {
|
if (action == 'delete') {
|
||||||
var selectedIndex = this.selection.count ? this.selection.currentIndex : 0;
|
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')
|
else if(action == 'move')
|
||||||
{
|
{
|
||||||
yield this.reload();
|
yield this.reload();
|
||||||
|
yield this.restoreSelection(currentTreeRow);
|
||||||
|
}
|
||||||
|
else if (action == 'modify') {
|
||||||
|
let row;
|
||||||
|
let id = ids[0];
|
||||||
|
|
||||||
// Open the new parent collection if closed
|
switch (type) {
|
||||||
for (var i=0; i<ids.length; i++) {
|
case 'collection':
|
||||||
var collection = yield Zotero.Collections.getAsync(ids[i]);
|
row = this.getRowIndexByID("C" + id);
|
||||||
var parentID = collection.parentID;
|
if (row !== false) {
|
||||||
if (parentID && this._rowMap["C" + parentID] &&
|
// TODO: Only move if name changed
|
||||||
!this.isContainerOpen(this._rowMap["C" + parentID])) {
|
let reopen = this.isContainerOpen(row);
|
||||||
yield this.toggleOpenState(this._rowMap["C" + parentID]);
|
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);
|
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);
|
||||||
}
|
}
|
||||||
else if (action == 'modify' || action == 'refresh') {
|
break;
|
||||||
if (type != 'bucket'
|
|
||||||
&& (type != 'publications' || this.selectedTreeRow.isPublications())) {
|
default:
|
||||||
yield this.reload();
|
yield this.reload();
|
||||||
|
yield this.restoreSelection(currentTreeRow);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.rememberSelection(savedSelection);
|
|
||||||
}
|
}
|
||||||
else if(action == 'add')
|
else if(action == 'add')
|
||||||
{
|
{
|
||||||
|
@ -388,11 +418,6 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
||||||
case 'search':
|
case 'search':
|
||||||
yield this._addSortedRow(type, id);
|
yield this._addSortedRow(type, id);
|
||||||
|
|
||||||
if (Zotero.suppressUIUpdates) {
|
|
||||||
this.rememberSelection(savedSelection);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectRow) {
|
if (selectRow) {
|
||||||
if (type == 'collection') {
|
if (type == 'collection') {
|
||||||
yield this.selectCollection(id);
|
yield this.selectCollection(id);
|
||||||
|
@ -407,7 +432,8 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
||||||
case 'group':
|
case 'group':
|
||||||
yield this.reload();
|
yield this.reload();
|
||||||
// Groups can only be created during sync
|
// Groups can only be created during sync
|
||||||
this.rememberSelection(savedSelection);
|
let libraryID = Zotero.Groups.getLibraryIDFromGroupID(id);
|
||||||
|
yield this.selectByID("L" + libraryID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,6 +448,10 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
||||||
* Add a row in the appropriate place
|
* Add a row in the appropriate place
|
||||||
*
|
*
|
||||||
* This only adds a row if it would be visible without opening any containers
|
* 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) {
|
Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(function* (objectType, id) {
|
||||||
let beforeRow;
|
let beforeRow;
|
||||||
|
@ -456,6 +486,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
|
||||||
else {
|
else {
|
||||||
// Get all collections at the same level that don't have a different parent
|
// Get all collections at the same level that don't have a different parent
|
||||||
startRow++;
|
startRow++;
|
||||||
|
loop:
|
||||||
for (let i = startRow; i < this.rowCount; i++) {
|
for (let i = startRow; i < this.rowCount; i++) {
|
||||||
let treeRow = this.getRow(i);
|
let treeRow = this.getRow(i);
|
||||||
beforeRow = i;
|
beforeRow = i;
|
||||||
|
@ -474,8 +505,8 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
|
||||||
// Fast forward through subcollections
|
// Fast forward through subcollections
|
||||||
while (rowLevel > level) {
|
while (rowLevel > level) {
|
||||||
beforeRow = ++i;
|
beforeRow = ++i;
|
||||||
if (i == this.rowCount) {
|
if (i == this.rowCount || !this.getRow(i).isCollection()) {
|
||||||
break;
|
break loop;
|
||||||
}
|
}
|
||||||
treeRow = this.getRow(i);
|
treeRow = this.getRow(i);
|
||||||
rowLevel = this.getLevel(i);
|
rowLevel = this.getLevel(i);
|
||||||
|
@ -533,7 +564,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
|
||||||
beforeRow
|
beforeRow
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return beforeRow;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -763,7 +794,7 @@ Zotero.CollectionTreeView.prototype.setCellText = function (row, col, val) {
|
||||||
}
|
}
|
||||||
var treeRow = this.getRow(row);
|
var treeRow = this.getRow(row);
|
||||||
treeRow.ref.name = val;
|
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
|
* @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
|
* Creates mapping of item group ids to tree rows
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -138,7 +138,7 @@ Zotero.LibraryTreeView.prototype = {
|
||||||
|
|
||||||
var lastRow = row == this.rowCount - 1;
|
var lastRow = row == this.rowCount - 1;
|
||||||
if (lastRow && this.selection.isSelected(row)) {
|
if (lastRow && this.selection.isSelected(row)) {
|
||||||
// Deslect removed row
|
// Deselect removed row
|
||||||
this.selection.toggleSelect(row);
|
this.selection.toggleSelect(row);
|
||||||
// If no other rows selected, select row before
|
// If no other rows selected, select row before
|
||||||
if (this.selection.count == 0 && row !== 0) {
|
if (this.selection.count == 0 && row !== 0) {
|
||||||
|
|
|
@ -1282,6 +1282,10 @@ var ZoteroPane = new function()
|
||||||
}
|
}
|
||||||
|
|
||||||
var collectionTreeRow = this.getCollectionTreeRow();
|
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
|
// Single item selected
|
||||||
if (this.itemsView.selection.count == 1 && this.itemsView.selection.currentIndex != -1)
|
if (this.itemsView.selection.count == 1 && this.itemsView.selection.currentIndex != -1)
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("Zotero.CollectionTreeView", function() {
|
describe("Zotero.CollectionTreeView", function() {
|
||||||
var win, cv;
|
var win, zp, cv;
|
||||||
|
|
||||||
before(function* () {
|
before(function* () {
|
||||||
win = yield loadZoteroPane();
|
win = yield loadZoteroPane();
|
||||||
cv = win.ZoteroPane.collectionsView;
|
zp = win.ZoteroPane;
|
||||||
|
cv = zp.collectionsView;
|
||||||
});
|
});
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
// TODO: Add a selectCollection() function and select a collection instead?
|
// 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);
|
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
|
// Create collection
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Reselect on modify";
|
collection.name = "Reselect on modify";
|
||||||
|
@ -154,6 +155,56 @@ describe("Zotero.CollectionTreeView", function() {
|
||||||
assert.equal(selected, id);
|
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* () {
|
it("should add a saved search after collections", function* () {
|
||||||
var collection = new Zotero.Collection;
|
var collection = new Zotero.Collection;
|
||||||
collection.name = "Test";
|
collection.name = "Test";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user