diff --git a/chrome/content/zotero/xpcom/collectionTreeView.js b/chrome/content/zotero/xpcom/collectionTreeView.js index 0216553da..803e0bb45 100644 --- a/chrome/content/zotero/xpcom/collectionTreeView.js +++ b/chrome/content/zotero/xpcom/collectionTreeView.js @@ -639,39 +639,47 @@ Zotero.CollectionTreeView.prototype.hasNextSibling = function(row, afterIndex) /* * Opens/closes the specified row */ -Zotero.CollectionTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(function* (row) -{ - var count = 0; - var thisLevel = this.getLevel(row); - - //this._treebox.beginUpdateBatch(); +Zotero.CollectionTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(function* (row) { if (this.isContainerOpen(row)) { - while((row + 1 < this._rows.length) && (this.getLevel(row + 1) > thisLevel)) - { - this._removeRow(row+1); - count--; - } - // Remove from the end of the row's children - this._treebox.rowCountChanged(row + 1 + Math.abs(count), count); + return this._closeContainer(row); } - else { - var treeRow = this.getRow(row); - if (treeRow.isLibrary(true) || treeRow.isCollection()) { - count = yield this._expandRow(this._rows, row, true); - } - this.rowCount += count; - this._treebox.rowCountChanged(row + 1, count); + + var count = 0; + + var treeRow = this.getRow(row); + if (treeRow.isLibrary(true) || treeRow.isCollection()) { + count = yield this._expandRow(this._rows, row, true); } + this.rowCount += count; + this._treebox.rowCountChanged(row + 1, count); // Toggle container open value - this._rows[row][1] = !this._rows[row][1]; + this._rows[row][1] = true; this._treebox.invalidateRow(row); - //this._treebox.endUpdateBatch(); this._refreshRowMap(); - yield this._rememberOpenStates(); }); +Zotero.CollectionTreeView.prototype._closeContainer = function (row) { + if (!this.isContainerOpen(row)) return; + + var count = 0; + var level = this.getLevel(row); + + // Remove child rows + while ((row + 1 < this._rows.length) && (this.getLevel(row + 1) > level)) { + this._removeRow(row + 1); + count--; + } + // Mark as removed from the end of the row's children + this._treebox.rowCountChanged(row + 1 + Math.abs(count), count); + + this._rows[row][1] = false; + this._treebox.invalidateRow(row); + this._refreshRowMap(); +} + + Zotero.CollectionTreeView.prototype.isSelectable = function (row, col) { var treeRow = this.getRow(row); switch (treeRow.type) { @@ -744,7 +752,7 @@ Zotero.CollectionTreeView.prototype.expandLibrary = Zotero.Promise.coroutine(fun }); -Zotero.CollectionTreeView.prototype.collapseLibrary = Zotero.Promise.coroutine(function* () { +Zotero.CollectionTreeView.prototype.collapseLibrary = function () { var selectedLibraryID = this.getSelectedLibraryID(); if (selectedLibraryID === false) { return; @@ -764,8 +772,8 @@ Zotero.CollectionTreeView.prototype.collapseLibrary = Zotero.Promise.coroutine(f found = true; - if (this.isContainer(i) && this.isContainerOpen(i)) { - yield this.toggleOpenState(i); + if (this.isContainer(i)) { + this._closeContainer(i); } } @@ -773,7 +781,7 @@ Zotero.CollectionTreeView.prototype.collapseLibrary = Zotero.Promise.coroutine(f // Select the collapsed library this.selectLibrary(selectedLibraryID); -}); +}; Zotero.CollectionTreeView.prototype.expandToCollection = Zotero.Promise.coroutine(function* (collectionID) { @@ -870,7 +878,7 @@ Zotero.CollectionTreeView.prototype.selectCollection = Zotero.Promise.coroutine( }); -Zotero.CollectionTreeView.prototype.selectTrash = function (libraryID) { +Zotero.CollectionTreeView.prototype.selectTrash = Zotero.Promise.coroutine(function* (libraryID) { if (Zotero.suppressUIUpdates) { Zotero.debug("UI updates suppressed -- not changing library selection"); return false; @@ -887,7 +895,7 @@ Zotero.CollectionTreeView.prototype.selectTrash = function (libraryID) { // If in My Library and it's collapsed, open it if (!libraryID && !this.isContainerOpen(0)) { - this.toggleOpenState(0); + yield this.toggleOpenState(0); } // Find library trash @@ -897,13 +905,13 @@ Zotero.CollectionTreeView.prototype.selectTrash = function (libraryID) { // If group header is closed, open it if (itemGroup.isHeader() && itemGroup.ref.id == 'group-libraries-header' && !this.isContainerOpen(i)) { - this.toggleOpenState(i); + yield this.toggleOpenState(i); continue; } if (itemGroup.isLibrary(true) && itemGroup.ref.libraryID == libraryID && !this.isContainerOpen(i)) { - this.toggleOpenState(i); + yield this.toggleOpenState(i); continue; } @@ -915,7 +923,7 @@ Zotero.CollectionTreeView.prototype.selectTrash = function (libraryID) { } return false; -} +}); /** @@ -1001,8 +1009,8 @@ Zotero.CollectionTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(f //collapse open collections for (let i=0; i this._waitAfter) yield Zotero.Promise.resolve(); - yield this.expandMatchParents(); @@ -254,7 +250,6 @@ Zotero.ItemTreeView.prototype.setTree = Zotero.Promise.coroutine(function* (tree this.collectionTreeRow.itemToSelect = null; } - delete this._waitAfter; Zotero.debug("Set tree in "+(Date.now()-start)+" ms"); this._initialized = true; @@ -323,7 +318,7 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f //this._treebox.beginUpdateBatch(); } var savedSelection = this.getSelectedItems(true); - var savedOpenState = yield this.saveOpenState(); + var savedOpenState = this._saveOpenState(); var oldCount = this.rowCount; var newSearchItemIDs = {}; @@ -372,8 +367,6 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f } } - if(this._waitAfter && Date.now() > this._waitAfter) yield Zotero.Promise.resolve(); - this._rows = newRows; this.rowCount = this._rows.length; var diff = this.rowCount - oldCount; @@ -1194,58 +1187,53 @@ Zotero.ItemTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(functio return; } - var count = 0; - var thisLevel = this.getLevel(row); - - // Close if (this.isContainerOpen(row)) { - while((row + 1 < this._rows.length) && (this.getLevel(row + 1) > thisLevel)) - { - this._removeRow(row+1); - count--; - } - // Remove from the end of the row's children - this._treebox.rowCountChanged(row + 1 + Math.abs(count), count); + return this._closeContainer(row, skipItemMapRefresh); } + + var count = 0; + var level = this.getLevel(row); + + // // Open - else { - var item = this.getRow(row).ref; - yield item.loadChildItems(); - - //Get children - var includeTrashed = this.collectionTreeRow.isTrash(); - var attachments = item.getAttachments(includeTrashed); - var notes = item.getNotes(includeTrashed); - - var newRows; - if(attachments && notes) - newRows = notes.concat(attachments); - else if(attachments) - newRows = attachments; - else if(notes) - newRows = notes; - - if (newRows) { - newRows = yield Zotero.Items.getAsync(newRows); - - for(var i = 0; i < newRows.length; i++) - { - count++; - this._addRow( - this._rows, - new Zotero.ItemTreeRow(newRows[i], thisLevel + 1, false), - row + i + 1 - ); - } - this.rowCount += count; - this._treebox.rowCountChanged(row + 1, count); - } + // + var item = this.getRow(row).ref; + yield item.loadChildItems(); + + //Get children + var includeTrashed = this.collectionTreeRow.isTrash(); + var attachments = item.getAttachments(includeTrashed); + var notes = item.getNotes(includeTrashed); + + var newRows; + if (attachments.length && notes.length) { + newRows = notes.concat(attachments); + } + else if (attachments.length) { + newRows = attachments; + } + else if (notes.length) { + newRows = notes; } - // Toggle container open value - this._rows[row].isOpen = !this._rows[row].isOpen; + if (newRows) { + newRows = yield Zotero.Items.getAsync(newRows); + + for (let i = 0; i < newRows.length; i++) { + count++; + this._addRow( + this._rows, + new Zotero.ItemTreeRow(newRows[i], level + 1, false), + row + i + 1 + ); + } + this.rowCount += count; + this._treebox.rowCountChanged(row + 1, count); + } - if (!count) { + this._rows[row].isOpen = true; + + if (count == 0) { return; } @@ -1258,6 +1246,39 @@ Zotero.ItemTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(functio }); +Zotero.ItemTreeView.prototype._closeContainer = function (row, skipItemMapRefresh) { + // isContainer == false shouldn't happen but does if an item is dragged over a closed + // container until it opens and then released, since the container is no longer in the same + // place when the spring-load closes + if (!this.isContainer(row)) return; + if (!this.isContainerOpen(row)) return; + + var count = 0; + var level = this.getLevel(row); + + // Remove child rows + while ((row + 1 < this._rows.length) && (this.getLevel(row + 1) > level)) { + this._removeRow(row+1); + count--; + } + // Mark as removed from the end of the row's children + this._treebox.rowCountChanged(row + 1 + Math.abs(count), count); + + this._rows[row].isOpen = false; + + if (count == 0) { + return; + } + + this._treebox.invalidateRow(row); + + if (!skipItemMapRefresh) { + Zotero.debug('Refreshing hash map'); + this._refreshItemRowMap(); + } +} + + Zotero.ItemTreeView.prototype.isSorted = function() { // We sort by the first column if none selected, so return true @@ -1320,11 +1341,11 @@ Zotero.ItemTreeView.prototype.sort = Zotero.Promise.coroutine(function* (itemID) } this._needsSort = false; - // Single child item sort -- just toggle parent open and closed + // 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]); - yield this.toggleOpenState(parentIndex); + this._closeContainer(parentIndex); yield this.toggleOpenState(parentIndex); return; } @@ -1527,7 +1548,7 @@ Zotero.ItemTreeView.prototype.sort = Zotero.Promise.coroutine(function* (itemID) //this._treebox.beginUpdateBatch(); } var savedSelection = this.getSelectedItems(true); - var openItemIDs = yield this.saveOpenState(true); + var openItemIDs = this._saveOpenState(true); // Single-row sort if (itemID) { @@ -1646,9 +1667,8 @@ Zotero.ItemTreeView.prototype.selectItem = Zotero.Promise.coroutine(function* (i // If parent is already open and we haven't found the item, the child // hasn't yet been added to the view, so close parent to allow refresh - if (this.isContainerOpen(parentRow)) { - yield this.toggleOpenState(parentRow); - } + this._closeContainer(parentRow); + // Open the parent yield this.toggleOpenState(parentRow); row = this._itemRowMap[id]; @@ -1792,8 +1812,8 @@ Zotero.ItemTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(functio // Collapse open items for (var i=0; i