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:
parent
f87d29a6b9
commit
5876debd36
|
@ -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;
|
||||
|
|
|
@ -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);"/>
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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...
|
||||
|
|
BIN
chrome/skin/default/zotero/treeitem-note-abstract.png
Normal file
BIN
chrome/skin/default/zotero/treeitem-note-abstract.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 631 B |
Loading…
Reference in New Issue
Block a user