Addresses #513, Deleted Items folder

Adds handling for parent/child items in trash -- non-deleted context items will appear in gray, and "Restore to Library" and the delete keystrokes won't be available if any of those are selected

Like other search views, Select All will select only the deleted items
This commit is contained in:
Dan Stillman 2009-01-29 01:14:46 +00:00
parent cb8e226ae9
commit 5e774efc42
5 changed files with 126 additions and 43 deletions

View file

@ -819,6 +819,7 @@ var ZoteroPane = new function()
} }
} }
function itemSelected() function itemSelected()
{ {
if (!Zotero.stateCheck()) { if (!Zotero.stateCheck()) {
@ -829,7 +830,8 @@ var ZoteroPane = new function()
// Display restore button if items selected in Trash // Display restore button if items selected in Trash
if (this.itemsView && this.itemsView.selection.count) { if (this.itemsView && this.itemsView.selection.count) {
document.getElementById('zotero-item-restore-button').hidden document.getElementById('zotero-item-restore-button').hidden
= !this.itemsView._itemGroup.isTrash(); = !this.itemsView._itemGroup.isTrash()
|| _nonDeletedItemsSelected(this.itemsView);
} }
var tabs = document.getElementById('zotero-view-tabs'); var tabs = document.getElementById('zotero-view-tabs');
@ -913,7 +915,27 @@ var ZoteroPane = new function()
label.value = Zotero.getString('pane.item.selected.zero'); label.value = Zotero.getString('pane.item.selected.zero');
} }
} }
}
/**
* Check if any selected items in the passed (trash) treeview are not deleted
*
* @param {nsITreeView}
* @return {Boolean}
*/
function _nonDeletedItemsSelected(itemsView) {
var start = {};
var end = {};
for (var i=0, len=itemsView.selection.getRangeCount(); i<len; i++) {
itemsView.selection.getRangeAt(i, start, end);
for (var j=start.value; j<=end.value; j++) {
if (!itemsView._getItemAtRow(j).ref.deleted) {
return true;
}
}
}
return false;
} }
@ -973,6 +995,19 @@ var ZoteroPane = new function()
this.itemsView._itemGroup.isShare()) { this.itemsView._itemGroup.isShare()) {
return; return;
} }
// Do nothing in trash view if any non-deleted items are selected
else if (this.itemsView._itemGroup.isTrash()) {
var start = {};
var end = {};
for (var i=0, len=this.itemsView.selection.getRangeCount(); i<len; i++) {
this.itemsView.selection.getRangeAt(i, start, end);
for (var j=start.value; j<=end.value; j++) {
if (!this.itemsView._getItemAtRow(j).ref.deleted) {
return;
}
}
}
}
} }
var eraseChildren = {value: true}; var eraseChildren = {value: true};
@ -981,15 +1016,16 @@ var ZoteroPane = new function()
var hasChildren; var hasChildren;
if (!this.getSelectedCollection()) { if (!this.getSelectedCollection()) {
var start = new Object(); var start = {};
var end = new Object(); var end = {};
for (var i=0, len=this.itemsView.selection.getRangeCount(); i<len; i++) { for (var i=0, len=this.itemsView.selection.getRangeCount(); i<len; i++) {
this.itemsView.selection.getRangeAt(i,start,end); this.itemsView.selection.getRangeAt(i, start, end);
for (var j=start.value; j<=end.value; j++) for (var j=start.value; j<=end.value; j++) {
if (this.itemsView._getItemAtRow(j).numChildren()) { if (this.itemsView._getItemAtRow(j).numChildren()) {
hasChildren = true; hasChildren = true;
break; break;
} }
}
} }
} }

View file

@ -1170,8 +1170,7 @@ Zotero.ItemGroup.prototype.setTags = function(tags)
* Returns TRUE if saved search, quicksearch or tag filter * Returns TRUE if saved search, quicksearch or tag filter
*/ */
Zotero.ItemGroup.prototype.isSearchMode = function() { Zotero.ItemGroup.prototype.isSearchMode = function() {
// Search if (this.isSearch() || this.isTrash()) {
if (this.isSearch()) {
return true; return true;
} }

View file

@ -269,13 +269,15 @@ Zotero.Item.prototype.loadPrimaryData = function(allowFail) {
break; break;
case 'numNotes': case 'numNotes':
colSQL = '(SELECT COUNT(*) FROM itemNotes ' colSQL = '(SELECT COUNT(*) FROM itemNotes INo '
+ 'WHERE sourceItemID=I.itemID) AS numNotes'; + 'WHERE sourceItemID=I.itemID AND INo.itemID '
+ 'NOT IN (SELECT itemID FROM deletedItems)) AS numNotes';
break; break;
case 'numAttachments': case 'numAttachments':
colSQL = '(SELECT COUNT(*) FROM itemAttachments ' colSQL = '(SELECT COUNT(*) FROM itemAttachments IA '
+ 'WHERE sourceItemID=I.itemID) AS numAttachments'; + 'WHERE sourceItemID=I.itemID AND IA.itemID '
+ 'NOT IN (SELECT itemID FROM deletedItems)) AS numAttachments';
break; break;
} }
if (colSQL) { if (colSQL) {
@ -326,7 +328,15 @@ Zotero.Item.prototype.loadFromRow = function(row, reload) {
// Only accept primary field data through loadFromRow() // Only accept primary field data through loadFromRow()
if (this.isPrimaryField(col)) { if (this.isPrimaryField(col)) {
//Zotero.debug("Setting field '" + col + "' to '" + row[col] + "' for item " + this.id); //Zotero.debug("Setting field '" + col + "' to '" + row[col] + "' for item " + this.id);
this['_' + col] = row[col] ? row[col] : ''; switch (col) {
case 'numNotes':
case 'numAttachments':
this['_' + col] = row[col] ? parseInt(row[col]) : 0;
break;
default:
this['_' + col] = row[col] ? row[col] : '';
}
} }
else { else {
Zotero.debug(col + ' is not a valid primary field'); Zotero.debug(col + ' is not a valid primary field');
@ -1895,8 +1905,8 @@ Zotero.Item.prototype.isRegularItem = function() {
} }
Zotero.Item.prototype.numChildren = function() { Zotero.Item.prototype.numChildren = function(includeTrashed) {
return this.numNotes() + this.numAttachments(); return this.numNotes(includeTrashed) + this.numAttachments(includeTrashed);
} }
@ -1996,9 +2006,12 @@ Zotero.Item.prototype.updateNote = function(text) {
/** /**
* Returns number of notes in item * Returns number of child notes of item
**/ *
Zotero.Item.prototype.numNotes = function() { * @param {Boolean} includeTrashed Include trashed child items in count
* @return {Integer}
*/
Zotero.Item.prototype.numNotes = function(includeTrashed) {
if (this.isNote()) { if (this.isNote()) {
throw ("numNotes() cannot be called on items of type 'note'"); throw ("numNotes() cannot be called on items of type 'note'");
} }
@ -2007,7 +2020,14 @@ Zotero.Item.prototype.numNotes = function() {
return 0; return 0;
} }
return this._numNotes; var deleted = 0;
if (includeTrashed) {
var sql = "SELECT COUNT(*) FROM itemNotes WHERE sourceItemID=? AND "
+ "itemID IN (SELECT itemID FROM deletedItems)";
deleted = parseInt(Zotero.DB.valueQuery(sql, this.id));
}
return this._numNotes + deleted;
} }
@ -2121,9 +2141,12 @@ Zotero.Item.prototype.setNote = function(text) {
/** /**
* Returns an array of note itemIDs for this item * Returns child notes of this item
**/ *
Zotero.Item.prototype.getNotes = function() { * @param {Boolean} includeTrashed Include trashed child items
* @return {Integer[]} Array of itemIDs, or FALSE if none
*/
Zotero.Item.prototype.getNotes = function(includeTrashed) {
if (this.isNote()) { if (this.isNote()) {
throw ("getNotes() cannot be called on items of type 'note'"); throw ("getNotes() cannot be called on items of type 'note'");
} }
@ -2134,6 +2157,9 @@ Zotero.Item.prototype.getNotes = function() {
var sql = "SELECT N.itemID, title FROM itemNotes N NATURAL JOIN items " var sql = "SELECT N.itemID, title FROM itemNotes N NATURAL JOIN items "
+ "WHERE sourceItemID=?"; + "WHERE sourceItemID=?";
if (!includeTrashed) {
sql += " AND N.itemID NOT IN (SELECT itemID FROM deletedItems)";
}
if (Zotero.Prefs.get('sortNotesChronologically')) { if (Zotero.Prefs.get('sortNotesChronologically')) {
sql += " ORDER BY dateAdded"; sql += " ORDER BY dateAdded";
@ -2191,9 +2217,12 @@ Zotero.Item.prototype.isAttachment = function() {
/** /**
* Returns number of files in item * Returns number of child attachments of item
**/ *
Zotero.Item.prototype.numAttachments = function() { * @param {Boolean} includeTrashed Include trashed child items in count
* @return {Integer}
*/
Zotero.Item.prototype.numAttachments = function(includeTrashed) {
if (this.isAttachment()) { if (this.isAttachment()) {
throw ("numAttachments() cannot be called on attachment items"); throw ("numAttachments() cannot be called on attachment items");
} }
@ -2202,7 +2231,14 @@ Zotero.Item.prototype.numAttachments = function() {
return 0; return 0;
} }
return this._numAttachments; var deleted = 0;
if (includeTrashed) {
var sql = "SELECT COUNT(*) FROM itemAttachments WHERE sourceItemID=? AND "
+ "itemID IN (SELECT itemID FROM deletedItems)";
deleted = parseInt(Zotero.DB.valueQuery(sql, this.id));
}
return this._numAttachments + deleted;
} }
@ -2680,10 +2716,12 @@ Zotero.Item.prototype.__defineGetter__('attachmentModificationTime', function ()
/** /**
* Returns an array of attachment itemIDs that have this item as a source, * Returns child attachments of this item
* or FALSE if none *
**/ * @param {Boolean} includeTrashed Include trashed child items
Zotero.Item.prototype.getAttachments = function() { * @return {Integer[]} Array of itemIDs, or FALSE if none
*/
Zotero.Item.prototype.getAttachments = function(includeTrashed) {
if (this.isAttachment()) { if (this.isAttachment()) {
throw ("getAttachments() cannot be called on attachment items"); throw ("getAttachments() cannot be called on attachment items");
} }
@ -2698,6 +2736,9 @@ Zotero.Item.prototype.getAttachments = function() {
+ "LEFT JOIN itemDataValues IDV " + "LEFT JOIN itemDataValues IDV "
+ "ON (ID.valueID=IDV.valueID) " + "ON (ID.valueID=IDV.valueID) "
+ "WHERE sourceItemID=?"; + "WHERE sourceItemID=?";
if (!includeTrashed) {
sql += " AND A.itemID NOT IN (SELECT itemID FROM deletedItems)";
}
if (Zotero.Prefs.get('sortAttachmentsChronologically')) { if (Zotero.Prefs.get('sortAttachmentsChronologically')) {
sql += " ORDER BY dateAdded"; sql += " ORDER BY dateAdded";

View file

@ -567,8 +567,10 @@ Zotero.Items = new function() {
// Should be the same as parts in Zotero.Item.loadPrimaryData // Should be the same as parts in Zotero.Item.loadPrimaryData
var sql = 'SELECT I.*, ' var sql = 'SELECT I.*, '
+ getFirstCreatorSQL() + ', ' + getFirstCreatorSQL() + ', '
+ "(SELECT COUNT(*) FROM itemNotes WHERE sourceItemID=I.itemID) AS numNotes, " + "(SELECT COUNT(*) FROM itemNotes INo WHERE sourceItemID=I.itemID AND "
+ "(SELECT COUNT(*) FROM itemAttachments WHERE sourceItemID=I.itemID) AS numAttachments " + "INo.itemID NOT IN (SELECT itemID FROM deletedItems)) AS numNotes, "
+ "(SELECT COUNT(*) FROM itemAttachments IA WHERE sourceItemID=I.itemID AND "
+ "IA.itemID NOT IN (SELECT itemID FROM deletedItems)) AS numAttachments "
+ 'FROM items I WHERE 1'; + 'FROM items I WHERE 1';
if (arguments[0]) { if (arguments[0]) {
sql += ' AND I.itemID IN (' + Zotero.join(arguments[0], ',') + ')'; sql += ' AND I.itemID IN (' + Zotero.join(arguments[0], ',') + ')';

View file

@ -586,7 +586,7 @@ Zotero.ItemTreeView.prototype.getCellText = function(row, column)
if(column.id == "zotero-items-column-numChildren") if(column.id == "zotero-items-column-numChildren")
{ {
var c = obj.numChildren(); var c = obj.numChildren(this._itemGroup.isTrash());
// Don't display '0' // Don't display '0'
if(c && parseInt(c) > 0) { if(c && parseInt(c) > 0) {
val = c; val = c;
@ -668,7 +668,9 @@ Zotero.ItemTreeView.prototype.isContainerEmpty = function(row)
if(this._sourcesOnly) { if(this._sourcesOnly) {
return true; return true;
} else { } else {
return (this._getItemAtRow(row).numNotes() == 0 && this._getItemAtRow(row).numAttachments() == 0); var includeTrashed = this._itemGroup.isTrash();
return (this._getItemAtRow(row).numNotes(includeTrashed) == 0
&& this._getItemAtRow(row).numAttachments(includeTrashed) == 0);
} }
} }
@ -727,8 +729,9 @@ Zotero.ItemTreeView.prototype.toggleOpenState = function(row, skipItemMapRefresh
else { else {
var item = this._getItemAtRow(row).ref; var item = this._getItemAtRow(row).ref;
//Get children //Get children
var attachments = item.getAttachments(); var includeTrashed = this._itemGroup.isTrash();
var notes = item.getNotes(); var attachments = item.getAttachments(includeTrashed);
var notes = item.getNotes(includeTrashed);
var newRows; var newRows;
if(attachments && notes) if(attachments && notes)
@ -891,6 +894,8 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
return field; return field;
} }
var includeTrashed = this._itemGroup.isTrash();
function rowSort(a,b) { function rowSort(a,b) {
var cmp, fieldA, fieldB; var cmp, fieldA, fieldB;
@ -915,7 +920,7 @@ Zotero.ItemTreeView.prototype.sort = function(itemID)
break; break;
case 'numChildren': case 'numChildren':
cmp = b.numChildren() - a.numChildren(); cmp = b.numChildren(includeTrashed) - a.numChildren(includeTrashed);
if (cmp) { if (cmp) {
return cmp; return cmp;
} }
@ -2273,26 +2278,26 @@ Zotero.ItemTreeView.TreeRow.prototype.getField = function(field, unformatted)
return this.ref.getField(field, unformatted, true); return this.ref.getField(field, unformatted, true);
} }
Zotero.ItemTreeView.TreeRow.prototype.numChildren = function() Zotero.ItemTreeView.TreeRow.prototype.numChildren = function(includeTrashed)
{ {
if(this.ref.isRegularItem()) if(this.ref.isRegularItem())
return this.ref.numChildren(); return this.ref.numChildren(includeTrashed);
else else
return 0; return 0;
} }
Zotero.ItemTreeView.TreeRow.prototype.numNotes = function() Zotero.ItemTreeView.TreeRow.prototype.numNotes = function(includeTrashed)
{ {
if(this.ref.isRegularItem()) if(this.ref.isRegularItem())
return this.ref.numNotes(); return this.ref.numNotes(includeTrashed);
else else
return 0; return 0;
} }
Zotero.ItemTreeView.TreeRow.prototype.numAttachments = function() Zotero.ItemTreeView.TreeRow.prototype.numAttachments = function(includeTrashed)
{ {
if(this.ref.isRegularItem()) if(this.ref.isRegularItem())
return this.ref.numAttachments(); return this.ref.numAttachments(includeTrashed);
else else
return 0; return 0;
} }