Fix placement of saved searches in collections tree

And unify row add/remove handling between collections tree and items
tree
This commit is contained in:
Dan Stillman 2015-05-07 18:18:48 -04:00
parent 67abbc8c4a
commit 2a69885b11
4 changed files with 221 additions and 238 deletions

View File

@ -136,7 +136,7 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
// Record open states before refreshing
if (this._rows) {
for (var i=0, len=this._rows.length; i<len; i++) {
var treeRow = this._rows[i][0]
var treeRow = this._rows[i];
if (treeRow.ref && treeRow.ref.id == 'commons-header') {
var commonsExpand = this.isContainerOpen(i);
}
@ -172,43 +172,51 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
var oldCount = this.rowCount || 0;
var newRows = [];
var self = this;
var added = 0;
//
// Add "My Library"
//
this._addRow(
this._addRowToArray(
newRows,
new Zotero.CollectionTreeRow('library', { libraryID: Zotero.Libraries.userLibraryID })
new Zotero.CollectionTreeRow('library', { libraryID: Zotero.Libraries.userLibraryID }),
added++
);
yield this._expandRow(newRows, 0);
added += yield this._expandRow(newRows, 0);
this._addRow(newRows, new Zotero.CollectionTreeRow('separator', false));
this._addRowToArray(newRows, new Zotero.CollectionTreeRow('separator', false), added++);
// Add "My Publications"
this._addRow(
this._addRowToArray(
newRows,
new Zotero.CollectionTreeRow('publications', {
libraryID: Zotero.Libraries.publicationsLibraryID
})
}),
added++
);
// Add groups
var groups = yield Zotero.Groups.getAll();
if (groups.length) {
this._addRow(newRows, new Zotero.CollectionTreeRow('separator', false));
var row = this._addRow(
this._addRowToArray(
newRows,
new Zotero.CollectionTreeRow('separator', false),
added++
);
this._addRowToArray(
newRows,
new Zotero.CollectionTreeRow('header', {
id: "group-libraries-header",
label: Zotero.getString('pane.collections.groupLibraries'),
libraryID: -1
}, 0)
}, 0),
added++
);
for (let i = 0, len = groups.length; i < len; i++) {
this._rowMap['L' + groups[i].libraryID] = this._addRow(
newRows, new Zotero.CollectionTreeRow('group', groups[i])
this._addRowToArray(
newRows,
new Zotero.CollectionTreeRow('group', groups[i]),
added++
);
}
}
@ -244,8 +252,8 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
return;
}
if (!this._collectionRowMap) {
Zotero.debug("Collection row map didn't exist in collectionTreeView.notify()");
if (!this._rowMap) {
Zotero.debug("Row map didn't exist in collectionTreeView.notify()");
return;
}
@ -326,9 +334,9 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
for (var i=0; i<ids.length; i++) {
var collection = yield Zotero.Collections.getAsync(ids[i]);
var parentID = collection.parentID;
if (parentID && this._collectionRowMap[parentID] &&
!this.isContainerOpen(this._collectionRowMap[parentID])) {
yield this.toggleOpenState(this._collectionRowMap[parentID]);
if (parentID && this._rowMap["C" + parentID] &&
!this.isContainerOpen(this._rowMap["C" + parentID])) {
yield this.toggleOpenState(this._rowMap["C" + parentID]);
}
}
@ -392,14 +400,14 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
let parentID = collection.parentID;
// If parent isn't visible, don't add
if (parentID && this._collectionRowMap[parentID] === undefined) {
if (parentID && this._rowMap["C" + parentID] === undefined) {
return false;
}
let libraryID = collection.libraryID;
let startRow;
if (parentID) {
startRow = this._collectionRowMap[parentID];
startRow = this._rowMap["C" + parentID];
}
else {
startRow = this._rowMap['L' + libraryID];
@ -450,9 +458,7 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
}
}
this._addRow(
this._rows,
new Zotero.CollectionTreeRow('collection', collection),
level,
new Zotero.CollectionTreeRow('collection', collection, level),
beforeRow
);
}
@ -476,37 +482,27 @@ Zotero.CollectionTreeView.prototype._addSortedRow = Zotero.Promise.coroutine(fun
var inSearches = false;
for (let i = startRow; i < this.rowCount; i++) {
let treeRow = this.getRow(i);
Zotero.debug(treeRow.id);
beforeRow = i;
// If we've moved on to a different library, stop
if (treeRow.ref.libraryID != libraryID) {
break;
}
// If we've reached something other than collections, stop
if (treeRow.isSearch()) {
inSearches = true;
// If current search sorts after, stop
if (Zotero.localeCompare(treeRow.ref.name, search.name) > 0) {
break;
}
}
// If we've found searches but then see something other than a search, stop
else if (inSearches) {
// If it's not a search and it's not a collection, stop
else if (!treeRow.isCollection()) {
break;
}
}
}
this._addRow(
this._rows,
new Zotero.CollectionTreeRow('search', search),
level,
new Zotero.CollectionTreeRow('search', search, level),
beforeRow
);
}
this.rowCount++;
this._treebox.rowCountChanged(beforeRow, 1);
this._refreshRowMap();
return true;
});
@ -525,7 +521,7 @@ Zotero.CollectionTreeView.prototype.setHighlightedRows = Zotero.Promise.coroutin
if (id[0] == 'C') {
id = id.substr(1);
yield this.expandToCollection(id);
row = this._collectionRowMap[id];
row = this._rowMap["C" + id];
}
if (row) {
this._highlightedRows[row] = true;
@ -621,11 +617,6 @@ Zotero.CollectionTreeView.prototype.isContainer = function(row)
return treeRow.isLibrary(true) || treeRow.isCollection() || treeRow.isPublications() || treeRow.isBucket();
}
Zotero.CollectionTreeView.prototype.isContainerOpen = function(row)
{
return this._rows[row][1];
}
/*
* Returns true if the collection has no child collections
*/
@ -653,11 +644,6 @@ Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row)
return true;
}
Zotero.CollectionTreeView.prototype.getLevel = function(row)
{
return this._rows[row][2];
}
Zotero.CollectionTreeView.prototype.getParentIndex = function(row)
{
var thisLevel = this.getLevel(row);
@ -798,7 +784,7 @@ Zotero.CollectionTreeView.prototype.expandToCollection = Zotero.Promise.coroutin
yield this.toggleOpenState(libraryRow);
}
var row = this._collectionRowMap[collectionID];
var row = this._rowMap["C" + collectionID];
if (row !== undefined) {
return true;
}
@ -809,7 +795,7 @@ Zotero.CollectionTreeView.prototype.expandToCollection = Zotero.Promise.coroutin
col = yield Zotero.Collections.getAsync(parentID);
}
for each(var id in path) {
row = this._collectionRowMap[id];
row = this._rowMap["C" + id];
if (!this.isContainerOpen(row)) {
yield this.toggleOpenState(row);
}
@ -957,8 +943,8 @@ Zotero.CollectionTreeView.prototype.getLastViewedRow = Zotero.Promise.coroutine(
var select = 0;
if (matches) {
if (matches[1] == 'C') {
if (this._collectionRowMap[matches[2]]) {
select = this._collectionRowMap[matches[2]];
if (this._rowMap["C" + matches[2]]) {
select = this._rowMap["C" + matches[2]];
}
// Search recursively
else {
@ -986,11 +972,11 @@ Zotero.CollectionTreeView.prototype.getLastViewedRow = Zotero.Promise.coroutine(
lastCol = par;
path.push(lastCol);
}
while (!this._collectionRowMap[lastCol] && failsafe > 0)
while (!this._rowMap["C" + lastCol] && failsafe > 0)
if (path.length) {
for (var i=path.length-1; i>=0; i--) {
var id = path[i];
var row = this._collectionRowMap[id];
var row = this._rowMap["C" + id];
if (!row) {
var msg = "Collection not found in tree in "
+ "Zotero.CollectionTreeView.setTree()";
@ -1000,8 +986,8 @@ Zotero.CollectionTreeView.prototype.getLastViewedRow = Zotero.Promise.coroutine(
}
if (!this.isContainerOpen(row)) {
yield this.toggleOpenState(row);
if (this._collectionRowMap[matches[2]]) {
select = this._collectionRowMap[matches[2]];
if (this._rowMap["C" + matches[2]]) {
select = this._rowMap["C" + matches[2]];
break;
}
}
@ -1081,8 +1067,8 @@ Zotero.CollectionTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(f
* Expand row based on last state, or manually from toggleOpenState()
*/
Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(function* (rows, row, forceOpen) {
var treeRow = rows[row][0];
var level = rows[row][2];
var treeRow = rows[row];
var level = rows[row].level;
var isLibrary = treeRow.isLibrary(true);
var isGroup = treeRow.isGroup();
var isCollection = treeRow.isCollection();
@ -1120,7 +1106,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
if (!forceOpen &&
(this._containerState[treeRow.id] === false
|| (isCollection && !this._containerState[treeRow.id]))) {
rows[row][1] = false;
rows[row].isOpen = false;
return 0;
}
@ -1129,7 +1115,7 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
// If this isn't a manual open, set the initial state depending on whether
// there are child nodes
if (!forceOpen) {
rows[row][1] = startOpen;
rows[row].isOpen = startOpen;
}
if (!startOpen) {
@ -1140,17 +1126,15 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
// Add collections
for (var i = 0, len = collections.length; i < len; i++) {
var newRow = this._addRow(
let beforeRow = row + 1 + newRows;
this._addRowToArray(
rows,
new Zotero.CollectionTreeRow('collection', collections[i]),
level + 1,
row + 1 + newRows
new Zotero.CollectionTreeRow('collection', collections[i], level + 1),
beforeRow
);
// Recursively expand child collections that should be open
newRows += yield this._expandRow(rows, newRow);
newRows++;
// Recursively expand child collections that should be open
newRows += yield this._expandRow(rows, beforeRow);
}
if (isCollection) {
@ -1159,14 +1143,22 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
// Add searches
for (var i = 0, len = savedSearches.length; i < len; i++) {
this._addRow(rows, new Zotero.CollectionTreeRow('search', savedSearches[i]), level + 1, row + 1 + newRows);
this._addRowToArray(
rows,
new Zotero.CollectionTreeRow('search', savedSearches[i], level + 1),
row + 1 + newRows
);
newRows++;
}
// Duplicate items
if (showDuplicates) {
let d = new Zotero.Duplicates(libraryID);
this._addRow(rows, new Zotero.CollectionTreeRow('duplicates', d), level + 1, row + 1 + newRows);
this._addRowToArray(
rows,
new Zotero.CollectionTreeRow('duplicates', d, level + 1),
row + 1 + newRows
);
newRows++;
}
@ -1177,7 +1169,11 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
s.name = Zotero.getString('pane.collections.unfiled');
s.addCondition('libraryID', 'is', libraryID);
s.addCondition('unfiled', 'true');
this._addRow(rows, new Zotero.CollectionTreeRow('unfiled', s), level + 1, row + 1 + newRows);
this._addRowToArray(
rows,
new Zotero.CollectionTreeRow('unfiled', s, level + 1),
row + 1 + newRows
);
newRows++;
}
@ -1187,7 +1183,11 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
var ref = {
libraryID: libraryID
};
this._addRow(rows, new Zotero.CollectionTreeRow('trash', ref), level + 1, row + 1 + newRows);
this._addRowToArray(
rows,
new Zotero.CollectionTreeRow('trash', ref, level + 1),
row + 1 + newRows
);
newRows++;
}
this._trashNotEmpty[libraryID] = !!deletedItems.length;
@ -1197,45 +1197,6 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
});
/*
* Called by various view functions to show a row
*/
Zotero.CollectionTreeView.prototype._addRow = function (rows, treeRow, level, beforeRow) {
if (!level) {
level = 0;
}
if (!beforeRow) {
beforeRow = rows.length;
}
rows.splice(beforeRow, 0, [treeRow, false, level]);
return beforeRow;
}
/*
* Called by view to hide specified row
*/
Zotero.CollectionTreeView.prototype._removeRow = function(row)
{
this._rows.splice(row,1);
this.rowCount--;
if (this.selection.isSelected(row)) {
this.selection.toggleSelect(row);
}
}
/**
* Returns Zotero.CollectionTreeRow at row
*/
Zotero.CollectionTreeView.prototype.getRow = function (row) {
return this._rows[row][0];
}
/**
* Returns libraryID or FALSE if not a library
*/
@ -1295,16 +1256,8 @@ Zotero.CollectionTreeView.prototype.rememberSelection = Zotero.Promise.coroutine
*/
Zotero.CollectionTreeView.prototype._refreshRowMap = function() {
this._rowMap = {};
this._collectionRowMap = {};
for (let i = 0, len = this.rowCount; i < len; i++) {
let treeRow = this.getRow(i);
this._rowMap[treeRow.id] = i;
// Collections get special treatment for now
if (treeRow.isCollection()) {
this._collectionRowMap[treeRow.ref.id] = i;
}
this._rowMap[this.getRow(i).id] = i;
}
}
@ -2197,10 +2150,12 @@ Zotero.CollectionTreeCache = {
})
};
Zotero.CollectionTreeRow = function(type, ref)
Zotero.CollectionTreeRow = function(type, ref, level, isOpen)
{
this.type = type;
this.ref = ref;
this.level = level || 0
this.isOpen = isOpen || false;
}

View File

@ -48,7 +48,6 @@ Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
this._ownerDocument = null;
this._needsSort = false;
this._rows = [];
this._cellTextCache = {};
this._itemImages = {};
@ -355,9 +354,8 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f
this._addRowToArray(
newRows,
new Zotero.ItemTreeRow(item, 0, false),
added + 1
added++
);
added++;
}
newSearchItemIDs[item.id] = true;
}
@ -369,9 +367,8 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f
this._addRowToArray(
newRows,
new Zotero.ItemTreeRow(item, 0, false),
added + 1
added++
);
added++;
}
}
@ -414,7 +411,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
return;
}
if (!this._itemRowMap) {
if (!this._rowMap) {
Zotero.debug("Item row map didn't exist in itemTreeView.notify()");
return;
}
@ -449,13 +446,13 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
if (extraData.column == 'title') {
delete this._itemImages[id];
}
this._treebox.invalidateCell(this._itemRowMap[id], col);
this._treebox.invalidateCell(this._rowMap[id], col);
}
}
else {
for each(var id in ids) {
delete this._itemImages[id];
this._treebox.invalidateRow(this._itemRowMap[id]);
this._treebox.invalidateRow(this._rowMap[id]);
}
}
}
@ -485,7 +482,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
}
// If refreshing a single item, clear caches and then unselect and reselect row
else if (savedSelection.length == 1 && savedSelection[0] == ids[0]) {
let row = this._itemRowMap[ids[0]];
let row = this._rowMap[ids[0]];
delete this._cellTextCache[row];
this.selection.clearSelection();
@ -541,7 +538,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
// On a delete in duplicates mode, just refresh rather than figuring
// out what to remove
if (collectionTreeRow.isDuplicates()) {
previousRow = this._itemRowMap[ids[0]];
previousRow = this._rowMap[ids[0]];
yield this.refresh();
madeChanges = true;
sort = true;
@ -561,7 +558,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
}
// Row might already be gone (e.g. if this is a child and
// 'modify' was sent to parent)
let row = this._itemRowMap[ids[i]];
let row = this._rowMap[ids[i]];
if (push && row !== undefined) {
// Don't remove child items from collections, because it's handled by 'modify'
if (action == 'remove' && this.getParentIndex(row) != -1) {
@ -622,7 +619,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
let item = items[i];
let id = item.id;
let row = this._itemRowMap[id];
let row = this._rowMap[id];
// Deleted items get a modify that we have to ignore when
// not viewing the trash
@ -654,7 +651,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
}
// If not moved from under one item to another, just resort the row,
// which also invalidates it and refreshes it
else if (!(parentItemID && parentIndex != -1 && this._itemRowMap[parentItemID] != parentIndex)) {
else if (!(parentItemID && parentIndex != -1 && this._rowMap[parentItemID] != parentIndex)) {
sort = id;
}
@ -734,7 +731,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
&& collectionTreeRow.ref.libraryID == item.libraryID)
|| (collectionTreeRow.isCollection() && item.inCollection(collectionTreeRow.ref.id)))
// if we haven't already added it to our hash map
&& this._itemRowMap[item.id] == null
&& this._rowMap[item.id] == null
// Regular item or standalone note/attachment
&& item.isTopLevelItem()) {
let beforeRow = this.rowCount;
@ -824,7 +821,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
else if (action == 'modify' && ids.length == 1 &&
savedSelection.length == 1 && savedSelection[0] == ids[0]) {
// If the item no longer matches the search term, clear the search
if (quicksearch && this._itemRowMap[ids[0]] == undefined) {
if (quicksearch && this._rowMap[ids[0]] == undefined) {
Zotero.debug('Selected item no longer matches quicksearch -- clearing');
quicksearch.value = '';
quicksearch.doCommand();
@ -847,7 +844,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
else
{
if (previousRow === false) {
previousRow = this._itemRowMap[ids[0]];
previousRow = this._rowMap[ids[0]];
}
if (sort) {
@ -1116,11 +1113,6 @@ Zotero.ItemTreeView.prototype.isContainer = function(row)
return this.getRow(row).ref.isRegularItem();
}
Zotero.ItemTreeView.prototype.isContainerOpen = function(row)
{
return this._rows[row].isOpen;
}
Zotero.ItemTreeView.prototype.isContainerEmpty = function(row)
{
if (this._sourcesOnly) {
@ -1135,11 +1127,6 @@ Zotero.ItemTreeView.prototype.isContainerEmpty = function(row)
return item.numNotes(includeTrashed) === 0 && item.numAttachments(includeTrashed) == 0;
}
Zotero.ItemTreeView.prototype.getLevel = function(row)
{
return this.getRow(row).level;
}
// Gets the index of the row's container, or -1 if none (top-level)
Zotero.ItemTreeView.prototype.getParentIndex = function(row)
{
@ -1296,13 +1283,13 @@ Zotero.ItemTreeView.prototype.cycleHeader = Zotero.Promise.coroutine(function* (
this.selection.selectEventsSuppressed = true;
var savedSelection = this.getSelectedItems(true);
if (savedSelection.length == 1) {
var pos = this._itemRowMap[savedSelection[0]] - this._treebox.getFirstVisibleRow();
var pos = this._rowMap[savedSelection[0]] - this._treebox.getFirstVisibleRow();
}
yield this.sort();
yield this.rememberSelection(savedSelection);
// If single row was selected, try to keep it in the same place
if (savedSelection.length == 1) {
var newRow = this._itemRowMap[savedSelection[0]];
var newRow = this._rowMap[savedSelection[0]];
// Calculate the last row that would give us a full view
var fullTop = Math.max(0, this._rows.length - this._treebox.getPageLength());
// Calculate the row that would give us the same position
@ -1327,9 +1314,9 @@ Zotero.ItemTreeView.prototype.sort = Zotero.Promise.coroutine(function* (itemID)
this._needsSort = false;
// Single child item sort -- just toggle parent closed and open
if (itemID && this._itemRowMap[itemID] &&
this.getRow(this._itemRowMap[itemID]).ref.parentKey) {
let parentIndex = this.getParentIndex(this._itemRowMap[itemID]);
if (itemID && this._rowMap[itemID] &&
this.getRow(this._rowMap[itemID]).ref.parentKey) {
let parentIndex = this.getParentIndex(this._rowMap[itemID]);
this._closeContainer(parentIndex);
yield this.toggleOpenState(parentIndex);
return;
@ -1537,7 +1524,7 @@ Zotero.ItemTreeView.prototype.sort = Zotero.Promise.coroutine(function* (itemID)
// Single-row sort
if (itemID) {
let row = this._itemRowMap[itemID];
let row = this._rowMap[itemID];
for (let i=0, len=this._rows.length; i<len; i++) {
if (i === row) {
continue;
@ -1604,10 +1591,10 @@ Zotero.ItemTreeView.prototype.selectItem = Zotero.Promise.coroutine(function* (i
// If no row map, we're probably in the process of switching collections,
// so store the item to select on the item group for later
if (!this._itemRowMap) {
if (!this._rowMap) {
if (this.collectionTreeRow) {
this.collectionTreeRow.itemToSelect = { id: id, expand: expand };
Zotero.debug("_itemRowMap not yet set; not selecting item");
Zotero.debug("_rowMap not yet set; not selecting item");
return false;
}
@ -1615,7 +1602,7 @@ Zotero.ItemTreeView.prototype.selectItem = Zotero.Promise.coroutine(function* (i
return false;
}
var row = this._itemRowMap[id];
var row = this._rowMap[id];
// Get the row of the parent, if there is one
var parentRow = null;
@ -1627,8 +1614,8 @@ Zotero.ItemTreeView.prototype.selectItem = Zotero.Promise.coroutine(function* (i
}
var parent = item.parentItemID;
if (parent && this._itemRowMap[parent] != undefined) {
parentRow = this._itemRowMap[parent];
if (parent && this._rowMap[parent] != undefined) {
parentRow = this._rowMap[parent];
}
// If row with id not visible, check to see if it's hidden under a parent
@ -1656,7 +1643,7 @@ Zotero.ItemTreeView.prototype.selectItem = Zotero.Promise.coroutine(function* (i
// Open the parent
yield this.toggleOpenState(parentRow);
row = this._itemRowMap[id];
row = this._rowMap[id];
}
// This function calls nsITreeSelection.select(), which triggers the <tree>'s 'onselect'
@ -1732,7 +1719,7 @@ Zotero.ItemTreeView.prototype.selectItems = function(ids) {
var rows = [];
for each(var id in ids) {
if(this._itemRowMap[id] !== undefined) rows.push(this._itemRowMap[id]);
if(this._rowMap[id] !== undefined) rows.push(this._rowMap[id]);
}
rows.sort(function (a, b) {
return a - b;
@ -1867,71 +1854,6 @@ Zotero.ItemTreeView.prototype.setFilter = Zotero.Promise.coroutine(function* (ty
});
/**
* Add a tree row to the main array, update the row count, tell the treebox that the row count
* changed, and update the row map
*
* @param {Array} newRows - Array to operate on
* @param {Zotero.ItemTreeRow} itemTreeRow
* @param {Number} beforeRow - Row index to insert new row before
*/
Zotero.ItemTreeView.prototype._addRow = function (itemTreeRow, beforeRow) {
this._addRowToArray(this._rows, itemTreeRow, beforeRow);
this.rowCount++;
this._treebox.rowCountChanged(beforeRow, 1);
// Increment all rows in map at or above insertion point
for (let i in this._itemRowMap) {
if (this._itemRowMap[j] >= beforeRow) {
this._itemRowMap[j]++
}
}
// Add new row to map
this._itemRowMap[itemTreeRow.id] = beforeRow;
}
/**
* Add a tree row into a given array
*
* @param {Array} array - Array to operate on
* @param {Zotero.ItemTreeRow} itemTreeRow
* @param {Number} beforeRow - Row index to insert new row before
*/
Zotero.ItemTreeView.prototype._addRowToArray = function (array, itemTreeRow, beforeRow) {
array.splice(beforeRow, 0, itemTreeRow);
}
/**
* Remove a row from the main array, decrement the row count, tell the treebox that the row
* count changed, delete the row from the map, and optionally update all rows above it in the map
*/
Zotero.ItemTreeView.prototype._removeRow = function (row, skipItemMapUpdate) {
var id = this._rows[row].id;
this._rows.splice(row, 1);
this.rowCount--;
this._treebox.rowCountChanged(row + 1, -1);
delete this._itemRowMap[id];
if (!skipItemMapUpdate) {
for (let i in this._itemRowMap) {
if (this._itemRowMap[i] > row) {
this._itemRowMap[i]--;
}
}
}
/*if (this.selection.isSelected(row)) {
this.selection.toggleSelect(row);
}*/
}
/*
* Returns a reference to the item at row (see Zotero.Item in data_access.js)
*/
Zotero.ItemTreeView.prototype.getRow = function(row) {
return this._rows[row];
}
/*
* Create map of item ids to row indexes
*/
@ -1946,7 +1868,7 @@ Zotero.ItemTreeView.prototype._refreshItemRowMap = function()
}
rowMap[id] = i;
}
this._itemRowMap = rowMap;
this._rowMap = rowMap;
}
@ -1972,8 +1894,8 @@ Zotero.ItemTreeView.prototype.rememberSelection = Zotero.Promise.coroutine(funct
}
for(var i=0; i < selection.length; i++)
{
if (this._itemRowMap[selection[i]] != null) {
this.selection.toggleSelect(this._itemRowMap[selection[i]]);
if (this._rowMap[selection[i]] != null) {
this.selection.toggleSelect(this._rowMap[selection[i]]);
}
// Try the parent
else {
@ -1987,10 +1909,10 @@ Zotero.ItemTreeView.prototype.rememberSelection = Zotero.Promise.coroutine(funct
continue;
}
if (this._itemRowMap[parent] != null) {
this._closeContainer(this._itemRowMap[parent]);
yield this.toggleOpenState(this._itemRowMap[parent]);
this.selection.toggleSelect(this._itemRowMap[selection[i]]);
if (this._rowMap[parent] != null) {
this._closeContainer(this._rowMap[parent]);
yield this.toggleOpenState(this._rowMap[parent]);
this.selection.toggleSelect(this._rowMap[selection[i]]);
}
}
}
@ -2045,7 +1967,7 @@ Zotero.ItemTreeView.prototype._saveOpenState = function (close) {
Zotero.ItemTreeView.prototype.rememberOpenState = Zotero.Promise.coroutine(function* (itemIDs) {
var rowsToOpen = [];
for each(var id in itemIDs) {
var row = this._itemRowMap[id];
var row = this._rowMap[id];
// Item may not still exist
if (row == undefined) {
continue;
@ -2111,8 +2033,8 @@ Zotero.ItemTreeView.prototype.saveFirstRow = function() {
Zotero.ItemTreeView.prototype.rememberFirstRow = function(firstRow) {
if (firstRow && this._itemRowMap[firstRow]) {
this._treebox.scrollToRow(this._itemRowMap[firstRow]);
if (firstRow && this._rowMap[firstRow]) {
this._treebox.scrollToRow(this._rowMap[firstRow]);
}
}
@ -2892,7 +2814,7 @@ Zotero.ItemTreeView.prototype.canDropCheck = function (row, orient, dataTransfer
// Don't allow children to be dragged within their own parents
var parentItemID = item.parentItemID;
var parentIndex = this._itemRowMap[parentItemID];
var parentIndex = this._rowMap[parentItemID];
if (row != -1 && this.getLevel(row) > 0) {
if (this.getRow(this.getParentIndex(row)).ref.id == parentItemID) {
return false;

View File

@ -28,6 +28,8 @@ Zotero.LibraryTreeView = function () {
this._listeners = {
load: []
};
this._rows = [];
this._rowMap = {};
};
Zotero.LibraryTreeView.prototype = {
@ -52,6 +54,79 @@ Zotero.LibraryTreeView.prototype = {
}),
/**
* Returns a reference to the tree row at a given row
*/
getRow: function(row) {
return this._rows[row];
},
/**
* Add a tree row to the main array, update the row count, tell the treebox that the row
* count changed, and update the row map
*
* @param {Array} newRows - Array to operate on
* @param {Zotero.ItemTreeRow} itemTreeRow
* @param {Number} [beforeRow] - Row index to insert new row before
*/
_addRow: function (treeRow, beforeRow) {
this._addRowToArray(this._rows, treeRow, beforeRow);
this.rowCount++;
this._treebox.rowCountChanged(beforeRow, 1);
// Increment all rows in map at or above insertion point
for (let i in this._rowMap) {
if (this._rowMap[i] >= beforeRow) {
this._rowMap[i]++
}
}
// Add new row to map
this._rowMap[treeRow.id] = beforeRow;
},
/**
* Add a tree row into a given array
*
* @param {Array} array - Array to operate on
* @param {Zotero.CollectionTreeRow|ItemTreeRow} treeRow
* @param {Number} beforeRow - Row index to insert new row before
*/
_addRowToArray: function (array, treeRow, beforeRow) {
array.splice(beforeRow, 0, treeRow);
},
/**
* Remove a row from the main array, decrement the row count, tell the treebox that the row
* count changed, delete the row from the map, and optionally update all rows above it in the map
*/
_removeRow: function (row, skipMapUpdate) {
var id = this._rows[row].id;
this._rows.splice(row, 1);
this.rowCount--;
this._treebox.rowCountChanged(row + 1, -1);
delete this._rowMap[id];
if (!skipMapUpdate) {
for (let i in this._rowMap) {
if (this._rowMap[i] > row) {
this._rowMap[i]--;
}
}
}
},
getLevel: function (row) {
return this._rows[row].level;
},
isContainerOpen: function(row) {
return this._rows[row].isOpen;
},
/**
* Called while a drag is over the tree
*/

View File

@ -94,5 +94,36 @@ describe("Zotero.CollectionTreeView", function() {
selected = collectionsView.getSelectedCollection(true);
assert.equal(selected, id);
});
it("should add a saved search after collections", function* () {
var collection = new Zotero.Collection;
collection.name = "Test";
var collectionID = yield collection.save();
var cv = win.ZoteroPane.collectionsView;
var search = new Zotero.Search;
search.name = "A Test Search";
search.addCondition('title', 'contains', 'test');
var searchID = yield search.save();
var collectionRow = cv._rowMap["C" + collectionID];
var searchRow = cv._rowMap["S" + searchID];
var duplicatesRow = cv._rowMap["D" + Zotero.Libraries.userLibraryID];
var unfiledRow = cv._rowMap["U" + Zotero.Libraries.userLibraryID];
assert.isAbove(searchRow, collectionRow);
// If there's a duplicates row or an unfiled row, add before those.
// Otherwise, add before the trash
if (duplicatesRow !== undefined) {
assert.isBelow(searchRow, duplicatesRow);
}
else if (unfiledRow !== undefined) {
assert.isBelow(searchRow, unfiledRow);
}
else {
var trashRow = cv._rowMap["T" + Zotero.Libraries.userLibraryID];
assert.isBelow(searchRow, trashRow);
}
})
})
})