Closes #362, Support abstracts

N.B.: Some changes from plan on ticket

New methods:

Item.setAbstract(true|false) -- make a note an abstract (and clear existing abstract if there is one for source item) or clear abstract status
Item.isAbstract() -- returns true if note is an abstract, false if not
Item.getAbstract() - get itemID of child abstract note or false if none
ZoteroPane.toggleAbstractForSelectedItem()

Changed methods:

Item.updateNoteCache(text, isAbstract)
Notes.add(note, sourceItemID, isAbstract)
Item.setSource() -- moving abstract note to another source with an existing abstract or setting as an independent note will make note not abstract

Other changes:

- Context menu options in items pane: "Set note as abstract" and "Unset note as abstract"
- Child notes are now displayed before child attachments so that abstract will be first
This commit is contained in:
Dan Stillman 2006-12-07 00:45:41 +00:00
parent f87d29a6b9
commit 5876debd36
7 changed files with 205 additions and 43 deletions

View File

@ -58,6 +58,7 @@ var ZoteroPane = new function()
this.onDoubleClick = onDoubleClick;
this.contextPopupShowing = contextPopupShowing;
this.openNoteWindow = openNoteWindow;
this.toggleAbstractForSelectedItem = toggleAbstractForSelectedItem
this.newNote = newNote;
this.addTextToNote = addTextToNote;
this.addItemFromPage = addItemFromPage;
@ -731,52 +732,69 @@ var ZoteroPane = new function()
if(itemsView && itemsView.selection.count > 0)
{
enable.push(0,1,2,4,5,6,7,8,9);
enable.push(0,1,2,4,5,7,8,9,10);
// Multiple items selected
if (itemsView.selection.count > 1)
{
var multiple = '.multiple';
hide.push(0,1,2,3);
hide.push(0,1,2,3,4);
}
// Single item selected
else
{
var item = itemsView._getItemAtRow(itemsView.selection.currentIndex);
if (item.ref.isRegularItem())
var item = itemsView._getItemAtRow(itemsView.selection.currentIndex).ref;
if (item.isRegularItem())
{
var itemID = item.ref.getID();
var itemID = item.getID();
menu.setAttribute('itemID', itemID);
show.push(0,1,2,3);
show.push(0,1,2,4);
hide.push(3); // abstract
}
else
{
hide.push(0,1,2,3);
hide.push(0,1,2);
// Abstract
if (item.isNote() && item.getSource()) {
show.push(3,4);
if (item.isAbstract()) {
menu.childNodes[3].setAttribute('label', Zotero.getString('pane.items.menu.abstract.unset'));
}
else {
menu.childNodes[3].setAttribute('label', Zotero.getString('pane.items.menu.abstract.set'));
}
}
else {
hide.push(3,4);
}
}
}
}
else
{
disable.push(0,1,2,4,5,7,8,9);
disable.push(0,1,2,5,6,8,9,10);
hide.push(3); // abstract
show.push(4); // separator
}
// Remove from collection
if (itemsView._itemGroup.isCollection())
{
menu.childNodes[4].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
show.push(4);
menu.childNodes[5].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
show.push(5);
}
else
{
hide.push(4);
hide.push(5);
}
// Plural if necessary
menu.childNodes[5].setAttribute('label', Zotero.getString('pane.items.menu.erase' + multiple));
menu.childNodes[7].setAttribute('label', Zotero.getString('pane.items.menu.export' + multiple));
menu.childNodes[8].setAttribute('label', Zotero.getString('pane.items.menu.createBib' + multiple));
menu.childNodes[9].setAttribute('label', Zotero.getString('pane.items.menu.generateReport' + multiple));
menu.childNodes[6].setAttribute('label', Zotero.getString('pane.items.menu.erase' + multiple));
menu.childNodes[8].setAttribute('label', Zotero.getString('pane.items.menu.export' + multiple));
menu.childNodes[9].setAttribute('label', Zotero.getString('pane.items.menu.createBib' + multiple));
menu.childNodes[10].setAttribute('label', Zotero.getString('pane.items.menu.generateReport' + multiple));
for (var i in disable)
{
@ -936,6 +954,20 @@ var ZoteroPane = new function()
window.open('chrome://zotero/content/note.xul?v=1'+(id ? '&id='+id : '')+(parent ? '&coll='+parent : ''),'','chrome,resizable,centerscreen');
}
function toggleAbstractForSelectedItem() {
var items = getSelectedItems();
if (itemsView.selection.count == 1 && items[0] && items[0].isNote()
&& items[0].getSource()) {
items[0].setAbstract(!items[0].isAbstract())
return true;
}
return false;
}
function addAttachmentFromDialog(link, id)
{
var nsIFilePicker = Components.interfaces.nsIFilePicker;

View File

@ -80,6 +80,7 @@
<menuitem label="&zotero.items.menu.attach.note;" oncommand="ZoteroPane.newNote(false, this.parentNode.getAttribute('itemID'))"/>
<menuitem label="&zotero.items.menu.attach.snapshot;" oncommand="ZoteroPane.addAttachmentFromPage(false, this.parentNode.getAttribute('itemID'));"/>
<menuitem label="&zotero.items.menu.attach.link;" oncommand="ZoteroPane.addAttachmentFromPage(true, this.parentNode.getAttribute('itemID'));"/>
<menuitem oncommand="ZoteroPane.toggleAbstractForSelectedItem()"/>
<menuseparator/>
<menuitem oncommand="ZoteroPane.deleteSelectedItem();"/>
<menuitem oncommand="ZoteroPane.deleteSelectedItem(true);"/>

View File

@ -49,8 +49,9 @@ Zotero.Item.prototype._init = function(){
this._changedCreators = new Zotero.Hash();
this._changedItemData = new Zotero.Hash();
this._noteData = null;
this._noteDataAccessTime = null;
this._noteText = null;
this._noteIsAbstract = null
this._noteAccessTime = null;
this._fileLinkMode = null;
}
@ -966,20 +967,17 @@ Zotero.Item.prototype.updateNote = function(text){
Zotero.DB.beginTransaction();
if (this.isNote()){
var sourceID = this.getSource();
if (sourceID)
{
var sql = "REPLACE INTO itemNotes (note, sourceItemID, itemID) "
+ "VALUES (?,?,?)";
var bindParams = [{string:text}, sourceID, this.getID()];
}
else
{
var sql = "REPLACE INTO itemNotes (note, itemID) VALUES (?,?)";
var bindParams = [{string:text}, this.getID()];
}
var sourceItemID = this.getSource();
}
else {
if (sourceItemID)
{
var sql = "REPLACE INTO itemNotes (note, sourceItemID, itemID, isAbstract) "
+ "VALUES (?,?,?,?)";
var bindParams = [{string:text}, sourceItemID, this.getID(), this.isAbstract() ? 1 : null];
}
else
{
var sql = "REPLACE INTO itemNotes (note, itemID) VALUES (?,?)";
var bindParams = [{string:text}, this.getID()];
}
@ -988,7 +986,7 @@ Zotero.Item.prototype.updateNote = function(text){
if (updated){
this.updateDateModified();
Zotero.DB.commitTransaction();
this.updateNoteCache(text);
this.updateNoteCache(text, this.isAbstract());
Zotero.Notifier.trigger('modify', 'item', this.getID());
}
@ -998,10 +996,11 @@ Zotero.Item.prototype.updateNote = function(text){
}
Zotero.Item.prototype.updateNoteCache = function(text){
Zotero.Item.prototype.updateNoteCache = function(text, isAbstract){
// Update cached values
this._noteData = text ? text : '';
this._noteText = text ? text : '';
if (this.isNote()){
this._noteIsAbstract = !!isAbstract;
this.setField('title', this._noteToTitle(), true);
}
}
@ -1065,6 +1064,14 @@ Zotero.Item.prototype.setSource = function(sourceItemID){
}
}
if (this.isAbstract()) {
// If making an independent note or if new item already has an
// abstract, clear abstract status
if (!sourceItemID || newItem.getAbstract()) {
this.setAbstract(false);
}
}
var sql = "UPDATE item" + Type + "s SET sourceItemID=? WHERE itemID=?";
var bindParams = [sourceItemID ? {int:sourceItemID} : null, this.getID()];
Zotero.DB.query(sql, bindParams);
@ -1125,16 +1132,16 @@ Zotero.Item.prototype.getNote = function(){
throw ("getNote() can only be called on notes and attachments");
}
if (this._noteData !== null){
if (this._noteText !== null){
// Store access time for later garbage collection
this._noteDataAccessTime = new Date();
return this._noteData;
this._noteAccessTime = new Date();
return this._noteText;
}
var sql = "SELECT note FROM itemNotes WHERE itemID=" + this.getID();
var note = Zotero.DB.valueQuery(sql);
this._noteData = note ? note : '';
this._noteText = note ? note : '';
return note ? note : '';
}
@ -1172,11 +1179,105 @@ Zotero.Item.prototype.getNotes = function(){
}
var sql = "SELECT itemID FROM itemNotes NATURAL JOIN items "
+ "WHERE sourceItemID=" + this.getID() + " ORDER BY dateAdded";
+ "WHERE sourceItemID=" + this.getID() + " ORDER BY isAbstract IS NULL, dateAdded";
return Zotero.DB.columnQuery(sql);
}
/*
* Return true if a note item is an abstract, false otherwise
*/
Zotero.Item.prototype.isAbstract = function() {
if (!this.isNote()) {
throw ("getAbstract() can only be called on note items");
}
if (!this.getID()) {
throw ("Cannot call isAbstract() on unsaved item");
}
if (this._noteIsAbstract !== null) {
return this._noteIsAbstract;
}
var sql = "SELECT isAbstract FROM itemNotes WHERE itemID=?";
var isAbstract = !!Zotero.DB.valueQuery(sql, this.getID());
this._noteIsAbstract = isAbstract;
return isAbstract;
}
/*
* Make a note item an abstract or clear abstract status
*/
Zotero.Item.prototype.setAbstract = function(set) {
if (!this.isNote()) {
throw ("setAbstract() can only be called on note items");
}
if (!this.getID()) {
throw ("Cannot call setAbstract() on unsaved item");
}
if (!!set == !!this.isAbstract()) {
Zotero.debug('Abstract status has not changed', 4);
return;
}
Zotero.DB.beginTransaction();
var sourceItemID = this.getSource();
if (!sourceItemID) {
Zotero.DB.rollbackTransaction();
throw ("Cannot make a non-child note an abstract");
}
if (set) {
// If existing abstract, clear it
var oldAbstractID = Zotero.Items.get(sourceItemID).getAbstract();
if (oldAbstractID) {
var oldAbstractItem = Zotero.Items.get(oldAbstractID);
oldAbstractItem.setAbstract(false);
}
}
var sql = "UPDATE itemNotes SET isAbstract=NULL WHERE sourceItemID=?";
Zotero.DB.query(sql, sourceItemID);
var sql = "UPDATE itemNotes SET isAbstract=? WHERE itemID=?";
Zotero.DB.valueQuery(sql, [set ? 1 : null, this.getID()]);
Zotero.DB.commitTransaction();
this._noteIsAbstract = !!set;
Zotero.Notifier.trigger('modify', 'item', [this.getID(), sourceItemID]);
}
/*
* Return the itemID of a parent item's abstract note, or false if none
*/
Zotero.Item.prototype.getAbstract = function() {
if (!this.isRegularItem()) {
throw ("getAbstract() can only be called on regular items");
}
if (!this.getID()) {
throw ("Cannot call getAbstract() on unsaved item");
}
var sql = "SELECT itemID FROM itemNotes WHERE sourceItemID=? AND isAbstract=1";
return Zotero.DB.valueQuery(sql, this.getID());
}
////////////////////////////////////////////////////////
//
@ -2142,7 +2243,7 @@ Zotero.Notes = new function(){
*
* Returns the itemID of the new note item
**/
function add(text, sourceItemID){
function add(text, sourceItemID, isAbstract){
Zotero.DB.beginTransaction();
if (sourceItemID){
@ -2157,21 +2258,32 @@ Zotero.Notes = new function(){
}
}
// If creating abstract, clear abstract status of existing abstract
// for source item
if (isAbstract && sourceItemID) {
var oldAbstractID = Zotero.Items.get(sourceItemID).getAbstract();
if (oldAbstractID) {
var oldAbstractItem = Zotero.Items.get(oldAbstractID);
oldAbstractItem.setAbstract(false);
}
}
var note = Zotero.Items.getNewItemByType(Zotero.ItemTypes.getID('note'));
note.save();
var sql = "INSERT INTO itemNotes VALUES (?,?,?)";
var sql = "INSERT INTO itemNotes VALUES (?,?,?,?)";
var bindParams = [
note.getID(),
(sourceItemID ? {int:sourceItemID} : null),
{string:text}
{string:text},
isAbstract ? 1 : null,
];
Zotero.DB.query(sql, bindParams);
Zotero.DB.commitTransaction();
// Switch to Zotero.Items version
var note = Zotero.Items.get(note.getID());
note.updateNoteCache(text);
note.updateNoteCache(text, isAbstract);
if (sourceItemID){
sourceItem.incrementNoteCount();

View File

@ -347,6 +347,10 @@ Zotero.ItemTreeView.prototype.getImageSrc = function(row, col)
}
}
if (itemType == 'note' && item.ref.isAbstract()) {
itemType = 'note-abstract';
}
// DEBUG: only have icons for some types so far
switch (itemType)
{
@ -371,6 +375,7 @@ Zotero.ItemTreeView.prototype.getImageSrc = function(row, col)
case 'map':
case 'newspaperArticle':
case 'note':
case 'note-abstract':
case 'podcast':
case 'radioBroadcast':
case 'report':
@ -458,7 +463,7 @@ Zotero.ItemTreeView.prototype.toggleOpenState = function(row)
var newRows;
if(attachments && notes)
newRows = attachments.concat(notes);
newRows = notes.concat(attachments);
else if(attachments)
newRows = attachments;
else if(notes)

View File

@ -681,6 +681,16 @@ Zotero.Schema = new function(){
Zotero.DB.query("CREATE INDEX translators_type ON translators(translatorType)");
Zotero.DB.query("DROP TABLE translatorsTemp");
}
if (i==13) {
Zotero.DB.query("CREATE TABLE itemNotesTemp (itemID INT, sourceItemID INT, note TEXT, PRIMARY KEY (itemID), FOREIGN KEY (itemID) REFERENCES items(itemID), FOREIGN KEY (sourceItemID) REFERENCES items(itemID))");
Zotero.DB.query("INSERT INTO itemNotesTemp SELECT * FROM itemNotes");
Zotero.DB.query("DROP TABLE itemNotes");
Zotero.DB.query("CREATE TABLE itemNotes (\n itemID INT,\n sourceItemID INT,\n note TEXT,\n isAbstract INT DEFAULT NULL,\n PRIMARY KEY (itemID),\n FOREIGN KEY (itemID) REFERENCES items(itemID),\n FOREIGN KEY (sourceItemID) REFERENCES items(itemID)\n);");
Zotero.DB.query("INSERT INTO itemNotes SELECT itemID, sourceItemID, note, NULL FROM itemNotesTemp");
Zotero.DB.query("CREATE INDEX itemNotes_sourceItemID ON itemNotes(sourceItemID)");
Zotero.DB.query("DROP TABLE itemNotesTemp");
}
}
_updateSchema('userdata');

View File

@ -15,6 +15,8 @@ pane.items.menu.remove = Remove Selected Item
pane.items.menu.remove.multiple = Remove Selected Items
pane.items.menu.erase = Delete Selected Item from Library...
pane.items.menu.erase.multiple = Delete Selected Items from Library...
pane.items.menu.abstract.set = Set Note as Abstract
pane.items.menu.abstract.unset = Unset Note as Abstract
pane.items.menu.export = Export Selected Item...
pane.items.menu.export.multiple = Export Selected Items...
pane.items.menu.createBib = Create Bibliography from Selected Item...

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B