Initial My Publications support
Adds a "My Publications" source after "My Library", implemented as a separate library. Top-level items can be dragged in and removed. (This doesn't currently work without disabling Quick Copy.) Also: - Make "Group Libraries" an unselectable header instead of a container, and don't indent group libraries - Fix relation purging, which maybe never worked - Pass only libraryID/key on deletes (which should speed them up) - Fix async item cloning/copying - Fix miscellaneous other bugs To-do: - Confirmation dialog on drag - API support
This commit is contained in:
parent
a9f010d547
commit
bf36a988e4
24 changed files with 405 additions and 223 deletions
|
@ -101,6 +101,9 @@ var ZoteroOverlay = new function()
|
|||
|
||||
observerService.addObserver(zoteroObserver, "browser-delayed-startup-finished", false);
|
||||
|
||||
// Set a flag for hi-res displays
|
||||
Zotero.hiDPI = window.devicePixelRatio > 1;
|
||||
|
||||
// Add a listener for toolbar change events
|
||||
window.addEventListener("customizationchange", onToolbarChange, false);
|
||||
|
||||
|
|
|
@ -1064,7 +1064,8 @@ Zotero.Attachments = new function(){
|
|||
throw ("Attachment is already in library " + libraryID);
|
||||
}
|
||||
|
||||
var newAttachment = attachment.clone(libraryID);
|
||||
attachment.loadItemData();
|
||||
var newAttachment = yield attachment.clone(libraryID);
|
||||
if (attachment.isImportedAttachment()) {
|
||||
// Attachment path isn't copied over by clone() if libraryID is different
|
||||
newAttachment.attachmentPath = attachment.attachmentPath;
|
||||
|
|
|
@ -42,8 +42,21 @@ Zotero.CollectionTreeView = function()
|
|||
this.hideSources = [];
|
||||
|
||||
this._highlightedRows = {};
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'trash', 'bucket'], 'collectionTreeView');
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(
|
||||
this,
|
||||
[
|
||||
'collection',
|
||||
'search',
|
||||
'publications',
|
||||
'share',
|
||||
'group',
|
||||
'trash',
|
||||
'bucket'
|
||||
],
|
||||
'collectionTreeView'
|
||||
);
|
||||
this._containerState = {};
|
||||
this._publicationsRow;
|
||||
this._duplicateLibraries = [];
|
||||
this._unfiledLibraries = [];
|
||||
this._trashNotEmpty = {};
|
||||
|
@ -164,37 +177,34 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
libraryID: Zotero.Libraries.userLibraryID
|
||||
};
|
||||
|
||||
// treeRow, level, beforeRow, startOpen
|
||||
//
|
||||
// Add "My Library"
|
||||
//
|
||||
// addRow(treeRow, level, beforeRow, startOpen)
|
||||
this._addRow(newRows, new Zotero.CollectionTreeRow('library', library), 0, 1);
|
||||
yield this._expandRow(newRows, 0);
|
||||
|
||||
// Add "My Publications"
|
||||
this._addRow(newRows, new Zotero.CollectionTreeRow('separator', false));
|
||||
this._addRow(newRows, new Zotero.CollectionTreeRow('publications', {
|
||||
libraryID: Zotero.Libraries.publicationsLibraryID
|
||||
}));
|
||||
this._publicationsRow = newRows.length - 1;
|
||||
|
||||
// Add groups
|
||||
var groups = yield Zotero.Groups.getAll();
|
||||
if (groups.length) {
|
||||
this._addRow(newRows, new Zotero.CollectionTreeRow('separator', false));
|
||||
var header = {
|
||||
var row = this._addRow(newRows, new Zotero.CollectionTreeRow('header', {
|
||||
id: "group-libraries-header",
|
||||
label: Zotero.getString('pane.collections.groupLibraries'),
|
||||
libraryID: -1,
|
||||
expand: Zotero.Promise.coroutine(function* (rows, beforeRow, groups) {
|
||||
if (!groups) {
|
||||
groups = yield Zotero.Groups.getAll();
|
||||
}
|
||||
var newRows = 0;
|
||||
for (var i = 0, len = groups.length; i < len; i++) {
|
||||
var row = self._addRow(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow('group', groups[i]),
|
||||
1,
|
||||
beforeRow ? beforeRow + newRows : null
|
||||
);
|
||||
newRows += 1 + ( yield self._expandRow(rows, row) );
|
||||
}
|
||||
return newRows;
|
||||
})
|
||||
}
|
||||
var row = this._addRow(newRows, new Zotero.CollectionTreeRow('header', header));
|
||||
if (this._containerState.HG) {
|
||||
newRows[row][1] = true;
|
||||
yield header.expand(newRows, null, groups);
|
||||
libraryID: -1
|
||||
}, 0));
|
||||
for (let i = 0, len = groups.length; i < len; i++) {
|
||||
var row = this._addRow(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('group', groups[i])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,7 +335,8 @@ Zotero.CollectionTreeView.prototype.notify = Zotero.Promise.coroutine(function*
|
|||
this.rememberSelection(savedSelection);
|
||||
}
|
||||
else if (action == 'modify' || action == 'refresh') {
|
||||
if (type != 'bucket') {
|
||||
if (type != 'bucket'
|
||||
&& (type != 'publications' || this.selectedTreeRow.isPublications())) {
|
||||
yield this.reload();
|
||||
}
|
||||
this.rememberSelection(savedSelection);
|
||||
|
@ -392,10 +403,21 @@ Zotero.CollectionTreeView.prototype.setHighlightedRows = Zotero.Promise.coroutin
|
|||
this._highlightedRows = {};
|
||||
this._treebox.invalidate();
|
||||
|
||||
for each(var id in ids) {
|
||||
yield this.expandToCollection(id);
|
||||
this._highlightedRows[this._collectionRowMap[id]] = true;
|
||||
this._treebox.invalidateRow(this._collectionRowMap[id]);
|
||||
if (!ids) return;
|
||||
for (let id of ids) {
|
||||
var row = null;
|
||||
if (id[0] == 'C') {
|
||||
id = id.substr(1);
|
||||
yield this.expandToCollection(id);
|
||||
row = this._collectionRowMap[id];
|
||||
}
|
||||
else if (id == 'P') {
|
||||
row = this._publicationsRow;
|
||||
}
|
||||
if (row) {
|
||||
this._highlightedRows[row] = true;
|
||||
this._treebox.invalidateRow(row);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -429,6 +451,8 @@ Zotero.CollectionTreeView.prototype.getCellText = function(row, column)
|
|||
|
||||
Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
|
||||
{
|
||||
var suffix = Zotero.hiDPI ? "@2x" : "";
|
||||
|
||||
var treeRow = this.getRow(row);
|
||||
var collectionType = treeRow.type;
|
||||
|
||||
|
@ -467,6 +491,9 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
|
|||
case 'collection':
|
||||
case 'search':
|
||||
return "chrome://zotero-platform/content/treesource-" + collectionType + ".png";
|
||||
|
||||
case 'publications':
|
||||
return "chrome://zotero/skin/treeitem-journalArticle" + suffix + ".png";
|
||||
}
|
||||
|
||||
return "chrome://zotero/skin/treesource-" + collectionType + ".png";
|
||||
|
@ -475,7 +502,7 @@ Zotero.CollectionTreeView.prototype.getImageSrc = function(row, col)
|
|||
Zotero.CollectionTreeView.prototype.isContainer = function(row)
|
||||
{
|
||||
var treeRow = this.getRow(row);
|
||||
return treeRow.isLibrary(true) || treeRow.isCollection() || treeRow.isHeader() || treeRow.isBucket();
|
||||
return treeRow.isLibrary(true) || treeRow.isCollection() || treeRow.isPublications() || treeRow.isBucket();
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.isContainerOpen = function(row)
|
||||
|
@ -492,9 +519,6 @@ Zotero.CollectionTreeView.prototype.isContainerEmpty = function(row)
|
|||
if (treeRow.isLibrary()) {
|
||||
return false;
|
||||
}
|
||||
if (treeRow.isHeader()) {
|
||||
return false;
|
||||
}
|
||||
if (treeRow.isBucket()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -559,10 +583,7 @@ Zotero.CollectionTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(f
|
|||
}
|
||||
else {
|
||||
var treeRow = this.getRow(row);
|
||||
if (treeRow.type == 'header') {
|
||||
count = yield treeRow.ref.expand(this._rows, row + 1);
|
||||
}
|
||||
else if (treeRow.isLibrary(true) || treeRow.isCollection()) {
|
||||
if (treeRow.isLibrary(true) || treeRow.isCollection()) {
|
||||
count = yield this._expandRow(this._rows, row, true);
|
||||
}
|
||||
this.rowCount += count;
|
||||
|
@ -581,8 +602,9 @@ Zotero.CollectionTreeView.prototype.toggleOpenState = Zotero.Promise.coroutine(f
|
|||
Zotero.CollectionTreeView.prototype.isSelectable = function (row, col) {
|
||||
var treeRow = this.getRow(row);
|
||||
switch (treeRow.type) {
|
||||
case 'separator':
|
||||
return false;
|
||||
case 'separator':
|
||||
case 'header':
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -741,14 +763,6 @@ Zotero.CollectionTreeView.prototype.selectLibrary = Zotero.Promise.coroutine(fun
|
|||
// Find library
|
||||
for (var i = 0; i < this.rowCount; i++) {
|
||||
var treeRow = this.getRow(i);
|
||||
|
||||
// If group header is closed, open it
|
||||
if (treeRow.isHeader() && treeRow.ref.id == 'group-libraries-header'
|
||||
&& !this.isContainerOpen(i)) {
|
||||
yield this.toggleOpenState(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (treeRow.ref && treeRow.ref.libraryID == libraryID) {
|
||||
this._treebox.ensureRowIsVisible(i);
|
||||
this.selection.select(i);
|
||||
|
@ -900,6 +914,10 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
var isCollection = treeRow.isCollection();
|
||||
var libraryID = treeRow.ref.libraryID;
|
||||
|
||||
if (treeRow.isPublications()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
var group = yield Zotero.Groups.getByLibraryID(libraryID);
|
||||
var collections = yield group.getCollections();
|
||||
|
@ -1259,7 +1277,6 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
var ids = data;
|
||||
var items = Zotero.Items.get(ids);
|
||||
var skip = true;
|
||||
Zotero.debug(ids);
|
||||
for each(var item in items) {
|
||||
// Can only drag top-level items
|
||||
if (!item.isTopLevelItem()) {
|
||||
|
@ -1281,6 +1298,15 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
continue;
|
||||
}
|
||||
|
||||
if (treeRow.isPublications() && treeRow.ref.libraryID != item.libraryID) {
|
||||
if (item.isAttachment() || item.isNote()) {
|
||||
Zotero.debug("Standalone attachments and notes cannot be added to My Publications");
|
||||
return false;
|
||||
}
|
||||
skip = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cross-library drag
|
||||
if (treeRow.ref.libraryID != item.libraryID) {
|
||||
// Only allow cross-library drag to root library and collections
|
||||
|
@ -1313,7 +1339,7 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
return true;
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
if (treeRow.isSearch()) {
|
||||
if (treeRow.isSearch() || treeRow.isPublications()) {
|
||||
return false;
|
||||
}
|
||||
if (dataType == 'application/x-moz-file') {
|
||||
|
@ -1330,6 +1356,10 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
return true;
|
||||
}
|
||||
else if (dataType == 'zotero/collection') {
|
||||
if (treeRow.isPublications()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let draggedCollectionID = data[0];
|
||||
let draggedCollection = Zotero.Collections.get(draggedCollectionID);
|
||||
|
||||
|
@ -1400,16 +1430,22 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
|||
if (linkedItem && !linkedItem.deleted) {
|
||||
// For drag to root, skip if linked item exists
|
||||
if (treeRow.isLibrary(true)) {
|
||||
Zotero.debug("Linked item " + linkedItem.key + " already exists "
|
||||
+ "in library " + treeRow.ref.libraryID);
|
||||
continue;
|
||||
}
|
||||
// For drag to collection
|
||||
else if (treeRow.isCollection()) {
|
||||
// skip if linked item is already in it
|
||||
if (treeRow.ref.hasItem(linkedItem.id)) {
|
||||
Zotero.debug("Linked item " + linkedItem.key + " already exists "
|
||||
+ "in collection");
|
||||
continue;
|
||||
}
|
||||
// or if linked item is a child item
|
||||
else if (!linkedItem.isTopLevelItem()) {
|
||||
Zotero.debug("Linked item " + linkedItem.key + " already exists "
|
||||
+ "as child item");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1420,8 +1456,7 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
|||
|
||||
// Intra-library drag
|
||||
|
||||
// Make sure there's at least one item that's not already
|
||||
// in this collection
|
||||
// Make sure there's at least one item that's not already in this destination
|
||||
if (treeRow.isCollection()) {
|
||||
if (treeRow.ref.hasItem(item.id)) {
|
||||
Zotero.debug("Item " + item.id + " already exists in collection");
|
||||
|
@ -1563,7 +1598,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
|
||||
// Create new clone item in target library
|
||||
var newItem = item.clone(targetLibraryID, false, !Zotero.Prefs.get('groups.copyTags'));
|
||||
var newItem = yield item.clone(targetLibraryID, false, !Zotero.Prefs.get('groups.copyTags'));
|
||||
var newItemID = yield newItem.save();
|
||||
|
||||
// Record link
|
||||
|
@ -1577,10 +1612,11 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
|
||||
// Child notes
|
||||
if (Zotero.Prefs.get('groups.copyChildNotes')) {
|
||||
yield item.loadChildItems();
|
||||
var noteIDs = item.getNotes();
|
||||
var notes = yield Zotero.Items.getAsync(noteIDs);
|
||||
for each(var note in notes) {
|
||||
let newNote = note.clone(targetLibraryID);
|
||||
let newNote = yield note.clone(targetLibraryID);
|
||||
newNote.parentID = newItemID;
|
||||
yield newNote.save()
|
||||
|
||||
|
@ -1617,11 +1653,11 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
}
|
||||
|
||||
Zotero.Attachments.copyAttachmentToLibrary(attachment, targetLibraryID, newItem.id);
|
||||
Zotero.Attachments.copyAttachmentToLibrary(attachment, targetLibraryID, newItemID);
|
||||
}
|
||||
}
|
||||
|
||||
return newID;
|
||||
return newItemID;
|
||||
});
|
||||
|
||||
var targetLibraryID = targetTreeRow.ref.libraryID;
|
||||
|
@ -1791,9 +1827,7 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
// Add items to target collection
|
||||
if (targetCollectionID) {
|
||||
var collection = yield Zotero.Collections.getAsync(targetCollectionID);
|
||||
Zotero.debug('adding');
|
||||
yield collection.addItems(newIDs);
|
||||
Zotero.debug('added');
|
||||
}
|
||||
|
||||
// If moving, remove items from source collection
|
||||
|
@ -1902,24 +1936,34 @@ Zotero.CollectionTreeView.prototype.isSorted = function() { return false;
|
|||
Zotero.CollectionTreeView.prototype.getRowProperties = function(row, prop) {
|
||||
var props = [];
|
||||
|
||||
if (this._highlightedRows[row]) {
|
||||
// <=Fx21
|
||||
if (prop) {
|
||||
var aServ = Components.classes["@mozilla.org/atom-service;1"].
|
||||
getService(Components.interfaces.nsIAtomService);
|
||||
prop.AppendElement(aServ.getAtom("highlighted"));
|
||||
}
|
||||
// Fx22+
|
||||
else {
|
||||
props.push("highlighted");
|
||||
}
|
||||
var treeRow = this.getRow(row);
|
||||
if (treeRow.isHeader()) {
|
||||
props.push("header");
|
||||
}
|
||||
else if (this._highlightedRows[row]) {
|
||||
props.push("highlighted");
|
||||
}
|
||||
|
||||
return props.join(" ");
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.getColumnProperties = function(col, prop) { }
|
||||
Zotero.CollectionTreeView.prototype.getCellProperties = function(row, col, prop) { }
|
||||
Zotero.CollectionTreeView.prototype.getColumnProperties = function(col, prop) {}
|
||||
|
||||
Zotero.CollectionTreeView.prototype.getCellProperties = function(row, col, prop) {
|
||||
var props = [];
|
||||
|
||||
var treeRow = this.getRow(row);
|
||||
if (treeRow.isHeader()) {
|
||||
props.push("header");
|
||||
props.push("notwisty");
|
||||
}
|
||||
else if (treeRow.isPublications()) {
|
||||
props.push("notwisty");
|
||||
}
|
||||
|
||||
return props.join(" ");
|
||||
|
||||
}
|
||||
Zotero.CollectionTreeView.prototype.isSeparator = function(index) {
|
||||
var source = this.getRow(index);
|
||||
return source.type == 'separator';
|
||||
|
@ -1965,6 +2009,9 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
|
|||
case 'search':
|
||||
return 'S' + this.ref.id;
|
||||
|
||||
case 'publications':
|
||||
return 'P';
|
||||
|
||||
case 'duplicates':
|
||||
return 'D' + this.ref.libraryID;
|
||||
|
||||
|
@ -1990,7 +2037,7 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
|
|||
Zotero.CollectionTreeRow.prototype.isLibrary = function (includeGlobal)
|
||||
{
|
||||
if (includeGlobal) {
|
||||
return this.type == 'library' || this.type == 'group';
|
||||
return this.type == 'library' || this.type == 'publications' || this.type == 'group';
|
||||
}
|
||||
return this.type == 'library';
|
||||
}
|
||||
|
@ -2022,6 +2069,10 @@ Zotero.CollectionTreeRow.prototype.isHeader = function () {
|
|||
return this.type == 'header';
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeRow.prototype.isPublications = function() {
|
||||
return this.type == 'publications';
|
||||
}
|
||||
|
||||
Zotero.CollectionTreeRow.prototype.isGroup = function() {
|
||||
return this.type == 'group';
|
||||
}
|
||||
|
@ -2059,7 +2110,7 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('editable', function () {
|
|||
if (this.isTrash() || this.isShare() || this.isBucket()) {
|
||||
return false;
|
||||
}
|
||||
if (!this.isWithinGroup()) {
|
||||
if (this.isPublications || !this.isWithinGroup()) {
|
||||
return true;
|
||||
}
|
||||
var libraryID = this.ref.libraryID;
|
||||
|
@ -2107,6 +2158,9 @@ Zotero.CollectionTreeRow.prototype.getName = function()
|
|||
case 'library':
|
||||
return Zotero.getString('pane.collections.library');
|
||||
|
||||
case 'publications':
|
||||
return Zotero.getString('pane.collections.publications');
|
||||
|
||||
case 'trash':
|
||||
return Zotero.getString('pane.collections.trash');
|
||||
|
||||
|
@ -2130,9 +2184,6 @@ Zotero.CollectionTreeRow.prototype.getItems = Zotero.Promise.coroutine(function*
|
|||
|
||||
case 'bucket':
|
||||
return this.ref.getItems();
|
||||
|
||||
case 'header':
|
||||
return [];
|
||||
}
|
||||
|
||||
var ids = yield this.getSearchResults();
|
||||
|
@ -2220,7 +2271,7 @@ Zotero.CollectionTreeRow.prototype.getSearchObject = Zotero.Promise.coroutine(fu
|
|||
yield s.addCondition('deleted', 'true');
|
||||
}
|
||||
else {
|
||||
throw ('Invalid search mode in Zotero.CollectionTreeRow.getSearchObject()');
|
||||
throw new Error('Invalid search mode in Zotero.CollectionTreeRow.getSearchObject()');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2263,9 +2314,6 @@ Zotero.CollectionTreeRow.prototype.getChildTags = Zotero.Promise.method(function
|
|||
|
||||
case 'bucket':
|
||||
return false;
|
||||
|
||||
case 'header':
|
||||
return false;
|
||||
}
|
||||
|
||||
return Zotero.Tags.getAllWithinSearchResults(this.getSearchResults(true));
|
||||
|
|
|
@ -606,7 +606,10 @@ Zotero.Collection.prototype.erase = function(deleteItems) {
|
|||
return Zotero.DB.executeTransaction(function* () {
|
||||
var descendents = yield this.getDescendents(false, null, true);
|
||||
var items = [];
|
||||
notifierData[this.id] = { old: this.toJSON() };
|
||||
notifierData[this.id] = {
|
||||
libraryID: this.libraryID,
|
||||
key: this.key
|
||||
};
|
||||
|
||||
var del = [];
|
||||
for(var i=0, len=descendents.length; i<len; i++) {
|
||||
|
@ -615,7 +618,10 @@ Zotero.Collection.prototype.erase = function(deleteItems) {
|
|||
collections.push(descendents[i].id);
|
||||
var c = yield this.ObjectsClass.getAsync(descendents[i].id);
|
||||
if (c) {
|
||||
notifierData[c.id] = { old: c.toJSON() };
|
||||
notifierData[c.id] = {
|
||||
libraryID: c.libraryID,
|
||||
key: c.key
|
||||
};
|
||||
}
|
||||
}
|
||||
// Descendent items
|
||||
|
|
|
@ -292,6 +292,7 @@ Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function
|
|||
var predicate = Zotero.Relations.linkedObjectPredicate;
|
||||
var uri = Zotero.URI['get' + this._ObjectType + 'URI'](this);
|
||||
|
||||
// Get all relations with this object as the subject or object
|
||||
var links = yield Zotero.Promise.all([
|
||||
Zotero.Relations.getSubject(false, predicate, uri),
|
||||
Zotero.Relations.getObject(uri, predicate, false)
|
||||
|
@ -311,7 +312,7 @@ Zotero.DataObject.prototype._getLinkedObject = Zotero.Promise.coroutine(function
|
|||
|
||||
for (let i=0; i<links.length; i++) {
|
||||
let link = links[i];
|
||||
if (link.indexOf(libraryObjectPrefix) == 0) {
|
||||
if (link.startsWith(libraryObjectPrefix)) {
|
||||
var obj = yield Zotero.URI['getURI' + this._ObjectType](link);
|
||||
if (!obj) {
|
||||
Zotero.debug("Referenced linked " + this._objectType + " '" + link + "' not found "
|
||||
|
@ -599,6 +600,7 @@ Zotero.DataObject.prototype.erase = Zotero.Promise.coroutine(function* () {
|
|||
yield this._erasePreCommit(env);
|
||||
}.bind(this))
|
||||
.catch(e => {
|
||||
Zotero.debug(e);
|
||||
return this._eraseRecoverFromFailure(env);
|
||||
});
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ Zotero.Item = function(itemTypeOrID) {
|
|||
this._fileExists = null;
|
||||
|
||||
this._deleted = null;
|
||||
this._publication = null;
|
||||
this._hasNote = null;
|
||||
|
||||
this._noteAccessTime = null;
|
||||
|
@ -1037,28 +1038,35 @@ Zotero.Item.prototype.removeCreator = function(orderIndex, allowMissing) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Zotero.defineProperty(Zotero.Item.prototype, 'deleted', {
|
||||
get: function() {
|
||||
if (!this.id) {
|
||||
return false;
|
||||
|
||||
// Define 'deleted' and 'publication' properties
|
||||
for (let name of ['deleted', 'publication']) {
|
||||
let prop = '_' + name;
|
||||
|
||||
Zotero.defineProperty(Zotero.Item.prototype, name, {
|
||||
get: function() {
|
||||
if (!this.id) {
|
||||
return false;
|
||||
}
|
||||
if (this[prop] !== null) {
|
||||
return this[prop];
|
||||
}
|
||||
this._requireData('primaryData');
|
||||
},
|
||||
set: function(val) {
|
||||
val = !!val;
|
||||
|
||||
if (this[prop] == val) {
|
||||
Zotero.debug(Zotero.Utilities.capitalize(name)
|
||||
+ " state hasn't changed for item " + this.id);
|
||||
return;
|
||||
}
|
||||
this._markFieldChange('publication', !!this[prop]);
|
||||
this._changed[name] = true;
|
||||
this[prop] = val;
|
||||
}
|
||||
if (this._deleted !== null) {
|
||||
return this._deleted;
|
||||
}
|
||||
this._requireData('primaryData');
|
||||
},
|
||||
set: function(val) {
|
||||
var deleted = !!val;
|
||||
|
||||
if (this._deleted == deleted) {
|
||||
Zotero.debug("Deleted state hasn't changed for item " + this.id);
|
||||
return;
|
||||
}
|
||||
this._markFieldChange('deleted', !!this._deleted);
|
||||
this._changed.deleted = true;
|
||||
this._deleted = deleted;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Zotero.Item.prototype.addRelatedItem = Zotero.Promise.coroutine(function* (itemID) {
|
||||
|
@ -1407,7 +1415,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
|||
|
||||
// Trashed status
|
||||
if (this._changed.deleted) {
|
||||
if (this.deleted) {
|
||||
if (this._deleted) {
|
||||
sql = "REPLACE INTO deletedItems (itemID) VALUES (?)";
|
||||
}
|
||||
else {
|
||||
|
@ -3710,14 +3718,14 @@ Zotero.Item.prototype.multiDiff = Zotero.Promise.coroutine(function* (otherItems
|
|||
* @param {Number} [libraryID] - libraryID of the new item, or the same as original if omitted
|
||||
* @param {Boolean} [skipTags=false] - Skip tags
|
||||
*/
|
||||
Zotero.Item.prototype.clone = function(libraryID, skipTags) {
|
||||
Zotero.Item.prototype.clone = Zotero.Promise.coroutine(function* (libraryID, skipTags) {
|
||||
Zotero.debug('Cloning item ' + this.id);
|
||||
|
||||
if (libraryID !== undefined && libraryID !== null && typeof libraryID !== 'number') {
|
||||
throw new Error("libraryID must be null or an integer");
|
||||
}
|
||||
|
||||
this._requireData('primaryData');
|
||||
yield this.loadPrimaryData();
|
||||
|
||||
if (libraryID === undefined || libraryID === null) {
|
||||
libraryID = this.libraryID;
|
||||
|
@ -3728,6 +3736,7 @@ Zotero.Item.prototype.clone = function(libraryID, skipTags) {
|
|||
newItem.libraryID = libraryID;
|
||||
newItem.setType(this.itemTypeID);
|
||||
|
||||
yield this.loadItemData();
|
||||
var fieldIDs = this.getUsedFields();
|
||||
for (let i = 0; i < fieldIDs.length; i++) {
|
||||
let fieldID = fieldIDs[i];
|
||||
|
@ -3736,9 +3745,11 @@ Zotero.Item.prototype.clone = function(libraryID, skipTags) {
|
|||
|
||||
// Regular item
|
||||
if (this.isRegularItem()) {
|
||||
yield this.loadCreators();
|
||||
newItem.setCreators(newItem.getCreators());
|
||||
}
|
||||
else {
|
||||
yield this.loadNote();
|
||||
newItem.setNote(this.getNote());
|
||||
if (sameLibrary) {
|
||||
var parent = this.parentKey;
|
||||
|
@ -3763,16 +3774,18 @@ Zotero.Item.prototype.clone = function(libraryID, skipTags) {
|
|||
}
|
||||
|
||||
if (!skipTags) {
|
||||
yield this.loadTags();
|
||||
newItem.setTags(this.getTags());
|
||||
}
|
||||
|
||||
if (sameLibrary) {
|
||||
// DEBUG: this will add reverse-only relateds too
|
||||
yield this.loadRelations();
|
||||
newItem.setRelations(this.getRelations());
|
||||
}
|
||||
|
||||
return newItem;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
|
@ -3791,7 +3804,10 @@ Zotero.Item.prototype._eraseInit = Zotero.Promise.coroutine(function* (env) {
|
|||
if (!proceed) return false;
|
||||
|
||||
env.deletedItemNotifierData = {};
|
||||
env.deletedItemNotifierData[this.id] = { old: this.toJSON() };
|
||||
env.deletedItemNotifierData[this.id] = {
|
||||
libraryID: this.libraryID,
|
||||
key: this.key
|
||||
};
|
||||
|
||||
return true;
|
||||
});
|
||||
|
@ -4572,9 +4588,9 @@ Zotero.Item.prototype._getRelatedItems = function () {
|
|||
// Pull out object values from related-item relations, turn into items, and pull out keys
|
||||
var keys = [];
|
||||
for (let i=0; i<relatedItemURIs.length; i++) {
|
||||
item = Zotero.URI.getURIItem(relatedItemURIs[i]);
|
||||
if (item) {
|
||||
keys.push(item.key);
|
||||
let {libraryID, key} = Zotero.URI.getURIItemLibraryKey(relatedItemURIs[i]);
|
||||
if (key) {
|
||||
keys.push(key);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
Zotero.Libraries = new function () {
|
||||
let _libraryData = {},
|
||||
_userLibraryID,
|
||||
_publicationsLibraryID,
|
||||
_libraryDataLoaded = false;
|
||||
|
||||
Zotero.defineProperty(this, 'userLibraryID', {
|
||||
|
@ -37,6 +38,15 @@ Zotero.Libraries = new function () {
|
|||
}
|
||||
});
|
||||
|
||||
Zotero.defineProperty(this, 'publicationsLibraryID', {
|
||||
get: function() {
|
||||
if (!_libraryDataLoaded) {
|
||||
throw new Error("Library data not yet loaded");
|
||||
}
|
||||
return _publicationsLibraryID;
|
||||
}
|
||||
});
|
||||
|
||||
this.init = Zotero.Promise.coroutine(function* () {
|
||||
// Library data
|
||||
var sql = "SELECT * FROM libraries";
|
||||
|
@ -47,6 +57,9 @@ Zotero.Libraries = new function () {
|
|||
if (row.libraryType == 'user') {
|
||||
_userLibraryID = row.libraryID;
|
||||
}
|
||||
else if (row.libraryType == 'publications') {
|
||||
_publicationsLibraryID = row.libraryID;
|
||||
}
|
||||
}
|
||||
_libraryDataLoaded = true;
|
||||
});
|
||||
|
@ -82,6 +95,10 @@ Zotero.Libraries = new function () {
|
|||
switch (type) {
|
||||
case 'user':
|
||||
return Zotero.getString('pane.collections.library');
|
||||
|
||||
case 'publications':
|
||||
return Zotero.getString('pane.collections.publications');
|
||||
|
||||
case 'group':
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
|
@ -147,6 +164,7 @@ Zotero.Libraries = new function () {
|
|||
var type = this.getType(libraryID);
|
||||
switch (type) {
|
||||
case 'user':
|
||||
case 'publications':
|
||||
return true;
|
||||
|
||||
case 'group':
|
||||
|
@ -164,6 +182,7 @@ Zotero.Libraries = new function () {
|
|||
var type = this.getType(libraryID);
|
||||
switch (type) {
|
||||
case 'user':
|
||||
case 'publications':
|
||||
return true;
|
||||
|
||||
case 'group':
|
||||
|
@ -184,7 +203,6 @@ Zotero.Libraries = new function () {
|
|||
return this.getType(libraryID) == 'group';
|
||||
}
|
||||
|
||||
|
||||
function parseDBRow(row) {
|
||||
return {
|
||||
type: row.libraryType,
|
||||
|
|
|
@ -51,8 +51,8 @@ Zotero.Relation.prototype.__defineSetter__('object', function (val) { this._set(
|
|||
|
||||
|
||||
Zotero.Relation.prototype._get = function (field) {
|
||||
if (this._id && !this._loaded) {
|
||||
this.load();
|
||||
if (!this._loaded) {
|
||||
throw new Error("Data not loaded for relation " + this._id);
|
||||
}
|
||||
return this['_' + field];
|
||||
}
|
||||
|
@ -214,7 +214,8 @@ Zotero.Relation.prototype.erase = Zotero.Promise.coroutine(function* () {
|
|||
|
||||
var deleteData = {};
|
||||
deleteData[this.id] = {
|
||||
old: this.serialize()
|
||||
libraryID: this.libraryID,
|
||||
key: Zotero.Utilities.Internal.md5(this.subject + "_" + this.predicate + "_" + this.object)
|
||||
}
|
||||
|
||||
var sql = "DELETE FROM relations WHERE ROWID=?";
|
||||
|
@ -249,15 +250,11 @@ Zotero.Relation.prototype.serialize = function () {
|
|||
var key = Zotero.Utilities.Internal.md5(this.subject + "_" + this.predicate + "_" + this.object);
|
||||
|
||||
var obj = {
|
||||
primary: {
|
||||
libraryID: this.libraryID,
|
||||
key: key,
|
||||
},
|
||||
fields: {
|
||||
subject: this.subject,
|
||||
predicate: this.predicate,
|
||||
object: this.object
|
||||
}
|
||||
libraryID: this.libraryID,
|
||||
key: key,
|
||||
subject: this.subject,
|
||||
predicate: this.predicate,
|
||||
object: this.object
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -183,7 +183,8 @@ Zotero.Relations = function () {
|
|||
var ids = yield Zotero.DB.columnQueryAsync(sql, params);
|
||||
|
||||
for (let i=0; i<ids.length; i++) {
|
||||
let relation = yield this.get(ids[i]);
|
||||
let relation = this.get(ids[i]);
|
||||
yield relation.load();
|
||||
yield relation.erase();
|
||||
}
|
||||
}.bind(this));
|
||||
|
@ -206,7 +207,8 @@ Zotero.Relations = function () {
|
|||
var ids = yield Zotero.DB.columnQueryAsync(sql, params);
|
||||
|
||||
for (let i=0; i<ids.length; i++) {
|
||||
let relation = yield this.get(ids[i]);
|
||||
let relation = this.get(ids[i]);
|
||||
yield relation.load();
|
||||
yield relation.erase();
|
||||
}
|
||||
}.bind(this));
|
||||
|
@ -214,6 +216,8 @@ Zotero.Relations = function () {
|
|||
|
||||
|
||||
this.purge = Zotero.Promise.coroutine(function* () {
|
||||
Zotero.debug("Purging relations");
|
||||
var t = new Date;
|
||||
var sql = "SELECT subject FROM relations WHERE predicate != ? "
|
||||
+ "UNION SELECT object FROM relations WHERE predicate != ?";
|
||||
var uris = yield Zotero.DB.columnQueryAsync(sql, [this.deletedItemPredicate, this.deletedItemPredicate]);
|
||||
|
@ -226,14 +230,15 @@ Zotero.Relations = function () {
|
|||
if (uri.indexOf(prefix) == -1) {
|
||||
continue;
|
||||
}
|
||||
if (uri.indexOf(/\/items\//) != -1 && !Zotero.URI.getURIItem(uri)) {
|
||||
this.eraseByURI(uri);
|
||||
if (uri.indexOf("/items/") != -1 && !Zotero.URI.getURIItemID(uri)) {
|
||||
yield this.eraseByURI(uri);
|
||||
}
|
||||
if (uri.indexOf(/\/collections\//) != -1 && !Zotero.URI.getURICollection(uri)) {
|
||||
this.eraseByURI(uri);
|
||||
if (uri.indexOf("/collections/") != -1 && !Zotero.URI.getURICollectionID(uri)) {
|
||||
yield this.eraseByURI(uri);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
Zotero.debug("Purged relations in " + ((new Date) - t) + "ms");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -3100,6 +3100,8 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = function(uris) {
|
|||
|
||||
// Next try getting URI directly
|
||||
try {
|
||||
// TEMP
|
||||
throw new Error("getURIItem() is now async");
|
||||
zoteroItem = Zotero.URI.getURIItem(uri);
|
||||
if(zoteroItem) {
|
||||
// Ignore items in the trash
|
||||
|
@ -3134,6 +3136,8 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = function(uris) {
|
|||
seen.push(uri);
|
||||
|
||||
try {
|
||||
// TEMP
|
||||
throw new Error("getURIItem() is now async");
|
||||
zoteroItem = Zotero.URI.getURIItem(uri);
|
||||
if(zoteroItem) {
|
||||
// Ignore items in the trash
|
||||
|
|
|
@ -476,6 +476,11 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
yield this.refresh();
|
||||
}
|
||||
}
|
||||
else if (type == 'publications') {
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
yield this.refresh();
|
||||
}
|
||||
}
|
||||
// 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]];
|
||||
|
@ -545,7 +550,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
var rows = [];
|
||||
for (var i=0, len=ids.length; i<len; i++) {
|
||||
let push = false;
|
||||
if (action == 'delete' && action == 'trash') {
|
||||
if (action == 'delete' || action == 'trash') {
|
||||
push = true;
|
||||
}
|
||||
else {
|
||||
|
@ -627,8 +632,15 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
var parentItemID = this.getRow(row).ref.parentItemID;
|
||||
var parentIndex = this.getParentIndex(row);
|
||||
|
||||
if (this.isContainer(row))
|
||||
{
|
||||
// Top-level item
|
||||
if (this.isContainer(row)) {
|
||||
// If removed from My Publications, remove row
|
||||
if (collectionTreeRow.isPublications() && !item.publication) {
|
||||
this._removeRow(row);
|
||||
this._treebox.rowCountChanged(row, -1)
|
||||
continue;
|
||||
}
|
||||
|
||||
//yield this.toggleOpenState(row);
|
||||
//yield this.toggleOpenState(row);
|
||||
sort = id;
|
||||
|
@ -1753,7 +1765,7 @@ Zotero.ItemTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(functio
|
|||
if (collectionTreeRow.isBucket()) {
|
||||
collectionTreeRow.ref.deleteItems(ids);
|
||||
}
|
||||
else if (collectionTreeRow.isTrash()) {
|
||||
else if (collectionTreeRow.isTrash() || collectionTreeRow.isPublications()) {
|
||||
Zotero.Items.erase(ids);
|
||||
}
|
||||
else if (collectionTreeRow.isLibrary(true) || force) {
|
||||
|
|
|
@ -105,6 +105,7 @@ Zotero.LibraryTreeView.prototype = {
|
|||
else {
|
||||
throw new Error("Invalid tree id '" + tree.id + "'");
|
||||
}
|
||||
|
||||
if (!view.canDropCheck(row.value, Zotero.DragDrop.currentOrientation, event.dataTransfer)) {
|
||||
this._setDropEffect(event, "none");
|
||||
return;
|
||||
|
|
|
@ -28,7 +28,8 @@ Zotero.Notifier = new function(){
|
|||
var _disabled = false;
|
||||
var _types = [
|
||||
'collection', 'search', 'share', 'share-items', 'item', 'file',
|
||||
'collection-item', 'item-tag', 'tag', 'setting', 'group', 'trash', 'bucket', 'relation'
|
||||
'collection-item', 'item-tag', 'tag', 'setting', 'group', 'trash', 'publications',
|
||||
'bucket', 'relation'
|
||||
];
|
||||
var _inTransaction;
|
||||
var _locked = false;
|
||||
|
@ -50,7 +51,7 @@ Zotero.Notifier = new function(){
|
|||
|
||||
for (var i=0; i<types.length; i++){
|
||||
if (_types.indexOf(types[i]) == -1){
|
||||
throw ('Invalid type ' + types[i] + ' in registerObserver()');
|
||||
throw new Error('Invalid type ' + types[i] + ' in registerObserver()');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ Zotero.Report.HTML = new function () {
|
|||
}
|
||||
for (let i=0; i<rels.length; i++) {
|
||||
let rel = rels[i];
|
||||
let relItem = Zotero.URI.getURIItem(rel);
|
||||
let relItem = yield Zotero.URI.getURIItem(rel);
|
||||
if (relItem) {
|
||||
content += '\t\t\t\t\t<li id="item_' + relItem.key + '">';
|
||||
content += escapeXML(relItem.getDisplayTitle());
|
||||
|
|
|
@ -1420,6 +1420,7 @@ Zotero.Schema = new function(){
|
|||
yield _updateDBVersion('compatibility', _maxCompatibility);
|
||||
|
||||
yield Zotero.DB.queryAsync("INSERT INTO libraries (libraryID, libraryType) VALUES (?, 'user')", userLibraryID);
|
||||
yield Zotero.DB.queryAsync("INSERT INTO libraries (libraryID, libraryType) VALUES (2, 'publications')");
|
||||
|
||||
if (!Zotero.Schema.skipDefaultData) {
|
||||
// Quick Start Guide web page item
|
||||
|
@ -1775,6 +1776,7 @@ Zotero.Schema = new function(){
|
|||
yield _updateDBVersion('compatibility', 1);
|
||||
|
||||
yield Zotero.DB.queryAsync("INSERT INTO libraries VALUES (1, 'user')");
|
||||
yield Zotero.DB.queryAsync("INSERT INTO libraries VALUES (2, 'publications')");
|
||||
|
||||
let oldUserLibraryID = yield Zotero.DB.valueQueryAsync("SELECT value FROM settings WHERE setting='account' AND key='libraryID'");
|
||||
|
||||
|
|
|
@ -1007,7 +1007,6 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
|
|||
continue;
|
||||
|
||||
case 'unfiled':
|
||||
this._conditions[i]['operator']
|
||||
var unfiled = this._conditions[i]['operator'] == 'true';
|
||||
continue;
|
||||
|
||||
|
@ -1704,7 +1703,10 @@ Zotero.Searches = function() {
|
|||
search.id = id;
|
||||
yield search.loadPrimaryData();
|
||||
yield search.loadConditions();
|
||||
notifierData[id] = { old: search.serialize() };
|
||||
notifierData[id] = {
|
||||
libraryID: this.libraryID,
|
||||
old: search.serialize() // TODO: replace with toJSON()
|
||||
};
|
||||
|
||||
var sql = "DELETE FROM savedSearchConditions WHERE savedSearchID=?";
|
||||
yield Zotero.DB.queryAsync(sql, id);
|
||||
|
@ -1712,7 +1714,7 @@ Zotero.Searches = function() {
|
|||
var sql = "DELETE FROM savedSearches WHERE savedSearchID=?";
|
||||
yield Zotero.DB.queryAsync(sql, id);
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
Zotero.Notifier.trigger('delete', 'search', ids, notifierData);
|
||||
});
|
||||
|
@ -1784,8 +1786,6 @@ Zotero.SearchConditions = new function(){
|
|||
//
|
||||
// Special conditions
|
||||
//
|
||||
|
||||
|
||||
{
|
||||
name: 'deleted',
|
||||
operators: {
|
||||
|
|
|
@ -301,14 +301,14 @@ Zotero.Sync.Storage.QueueManager = new function () {
|
|||
}
|
||||
|
||||
|
||||
function _reconcileConflicts(conflicts) {
|
||||
var _reconcileConflicts = Zotero.Promise.coroutine(function* (conflicts) {
|
||||
var objectPairs = [];
|
||||
for each(var conflict in conflicts) {
|
||||
var item = Zotero.Sync.Storage.getItemFromRequestName(conflict.name);
|
||||
var item1 = item.clone(false, false, true);
|
||||
var item1 = yield item.clone(false, false, true);
|
||||
item1.setField('dateModified',
|
||||
Zotero.Date.dateToSQL(new Date(conflict.localData.modTime), true));
|
||||
var item2 = item.clone(false, false, true);
|
||||
var item2 = yield item.clone(false, false, true);
|
||||
item2.setField('dateModified',
|
||||
Zotero.Date.dateToSQL(new Date(conflict.remoteData.modTime), true));
|
||||
objectPairs.push([item1, item2]);
|
||||
|
@ -342,7 +342,7 @@ Zotero.Sync.Storage.QueueManager = new function () {
|
|||
}
|
||||
|
||||
return io.dataOut;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function _processMergeData(data) {
|
||||
|
|
|
@ -86,10 +86,15 @@ Zotero.URI = new function () {
|
|||
|
||||
switch (libraryType) {
|
||||
case 'user':
|
||||
case 'publications':
|
||||
var id = Zotero.Users.getCurrentUserID();
|
||||
if (!id) {
|
||||
throw new Exception("User id not available in Zotero.URI.getLibraryPath()");
|
||||
}
|
||||
|
||||
if (libraryType == 'publications') {
|
||||
return "users/" + id + "/publications";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
|
@ -171,49 +176,92 @@ Zotero.URI = new function () {
|
|||
*
|
||||
* @param {String} itemURI
|
||||
* @param {Zotero.Item|FALSE}
|
||||
* @return {Promise<Zotero.Item|FALSE>}
|
||||
*/
|
||||
this.getURIItem = function (itemURI) {
|
||||
this.getURIItem = Zotero.Promise.method(function (itemURI) {
|
||||
var {libraryID, key} = this._getURIObject(itemURI, 'item');
|
||||
if (!key) return false;
|
||||
return Zotero.Items.getByLibraryAndKeyAsync(libraryID, key);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} itemURI
|
||||
* @return {Object|FALSE} - Object with 'libraryID' and 'key', or FALSE if item not found
|
||||
*/
|
||||
this.getURIItemLibraryKey = function (itemURI) {
|
||||
return this._getURIObject(itemURI, 'item');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} itemURI
|
||||
* @return {Integer|FALSE} - itemID of matching item, or FALSE if none
|
||||
*/
|
||||
this.getURIItemID = function (itemURI) {
|
||||
var {libraryID, key} = this._getURIObject(itemURI, 'item');
|
||||
if (!key) return false;
|
||||
return Zotero.Items.getIDFromLibraryAndKey(libraryID, key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a collection URI into a collection
|
||||
*
|
||||
* @param {String} collectionURI
|
||||
* @param {Zotero.Collection|FALSE}
|
||||
* @return {Promise<Zotero.Collection|FALSE>}
|
||||
*/
|
||||
this.getURICollection = function (collectionURI) {
|
||||
this.getURICollection = Zotero.Promise.method(function (collectionURI) {
|
||||
var {libraryID, key} = this._getURIObject(collectionURI, 'collection');
|
||||
if (!key) return false;
|
||||
return Zotero.Collections.getByLibraryAndKeyAsync(libraryID, key);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} collectionURI
|
||||
* @return {Object|FALSE} - Object with 'libraryID' and 'key', or FALSE if item not found
|
||||
*/
|
||||
this.getURICollectionLibraryKey = function (collectionURI) {
|
||||
return this._getURIObject(collectionURI, 'collection');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} collectionURI
|
||||
* @return {Integer|FALSE} - collectionID of matching collection, or FALSE if none
|
||||
*/
|
||||
this.getURICollectionID = function (collectionURI) {
|
||||
var {libraryID, key} = this._getURIObject(collectionURI, 'item');
|
||||
if (!key) return false;
|
||||
return Zotero.Collections.getIDFromLibraryAndKey(libraryID, key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a library URI into a libraryID
|
||||
*
|
||||
* @param {String} libraryURI
|
||||
* @return {Zotero.Collection|FALSE}
|
||||
* @return {Integer|FALSE} - libraryID, or FALSE if no matching library
|
||||
*/
|
||||
this.getURILibrary = function (libraryURI) {
|
||||
return this._getURIObject(libraryURI, "library");
|
||||
var {libraryID} = this._getURIObject(libraryURI, "library");
|
||||
return libraryID !== undefined ? libraryID : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert an object URI into an object (item, collection, etc.)
|
||||
*
|
||||
* @param {String} objectURI
|
||||
* @param {"item"|"collection"|"library"} [type] The type of object to return. If the object
|
||||
* is valid but not available, returns "false". Note that if type is "library", this
|
||||
* this function may return null for the default library, which is distinct from false.
|
||||
*
|
||||
* @return {Zotero.Item|Zotero.Collection|Integer|NULL|FALSE}
|
||||
* @param {String} objectURI
|
||||
* @param {'library'|'collection'|'item'} - The type of URI to expect
|
||||
* @return {Object|FALSE} - An object containing 'libraryID' and, if applicable, 'key',
|
||||
* or FALSE if library not found
|
||||
*/
|
||||
this._getURIObject = function (objectURI, type) {
|
||||
var Types = type[0].toUpperCase() + type.substr(1) + 's';
|
||||
var types = Types.toLowerCase();
|
||||
|
||||
var libraryType = null;
|
||||
var libraryType;
|
||||
var libraryTypeID;
|
||||
|
||||
// If this is a local URI, compare to the local user key
|
||||
if (objectURI.match(/\/users\/local\//)) {
|
||||
|
@ -229,72 +277,82 @@ Zotero.URI = new function () {
|
|||
}
|
||||
}
|
||||
*/
|
||||
var libraryType = 'user';
|
||||
var id = null;
|
||||
libraryType = 'user';
|
||||
libraryTypeID = null;
|
||||
}
|
||||
|
||||
// If not found, try global URI
|
||||
if (!libraryType) {
|
||||
if (objectURI.indexOf(_baseURI) != 0) {
|
||||
throw ("Invalid base URI '" + objectURI + "' in Zotero.URI._getURIObject()");
|
||||
if (!objectURI.startsWith(_baseURI)) {
|
||||
throw new Error("Invalid base URI '" + objectURI + "'");
|
||||
}
|
||||
objectURI = objectURI.substr(_baseURI.length);
|
||||
var typeRE = /^(users|groups)\/([0-9]+)(?:\/|$)/;
|
||||
var matches = objectURI.match(typeRE);
|
||||
let typeRE = /^(users|groups)\/([0-9]+)(?:\/|$)/;
|
||||
let matches = objectURI.match(typeRE);
|
||||
if (!matches) {
|
||||
throw ("Invalid library URI '" + objectURI + "' in Zotero.URI._getURIObject()");
|
||||
throw new Error("Invalid library URI '" + objectURI + "'");
|
||||
}
|
||||
var libraryType = matches[1].substr(0, matches[1].length-1);
|
||||
var id = matches[2];
|
||||
libraryType = matches[1].substr(0, matches[1].length-1);
|
||||
libraryTypeID = matches[2];
|
||||
objectURI = objectURI.replace(typeRE, '');
|
||||
}
|
||||
|
||||
if (libraryType == 'group') {
|
||||
if (!Zotero.Groups.get(id)) {
|
||||
if (libraryType == 'user' && objectURI.startsWith('publications/')) {
|
||||
libraryType = 'publications';
|
||||
}
|
||||
|
||||
if (libraryType == 'user') {
|
||||
var libraryID = Zotero.Libraries.userLibraryID;
|
||||
}
|
||||
else if (libraryType == 'group') {
|
||||
if (!Zotero.Groups.exists(libraryTypeID)) {
|
||||
return false;
|
||||
}
|
||||
var libraryID = Zotero.Groups.getLibraryIDFromGroupID(id);
|
||||
var libraryID = Zotero.Groups.getLibraryIDFromGroupID(libraryTypeID);
|
||||
}
|
||||
else if (libraryType == 'publications') {
|
||||
var libraryID = Zotero.Libraries.publicationsLibraryID;
|
||||
}
|
||||
|
||||
if(type === 'library') {
|
||||
if (libraryType == 'user') {
|
||||
if(id === null) {
|
||||
if (libraryTypeID) {
|
||||
if (libraryTypeID == Zotero.Users.getCurrentUserID()) {
|
||||
return {
|
||||
libraryID: libraryID
|
||||
};
|
||||
}
|
||||
}
|
||||
else {
|
||||
var localUserURI = this.getLocalUserURI();
|
||||
if (localUserURI) {
|
||||
localUserURI += "/";
|
||||
if (objectURI.indexOf(localUserURI) == 0) {
|
||||
objectURI = objectURI.substr(localUserURI.length);
|
||||
return null;
|
||||
if (objectURI.startsWith(localUserURI)) {
|
||||
return {
|
||||
libraryID: Zotero.Libraries.userLibraryID
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(id == Zotero.Users.getCurrentUserID()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (libraryType == 'group') {
|
||||
return libraryID;
|
||||
return {
|
||||
libraryID: libraryID
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// TODO: objectID-based URI?
|
||||
var re = new RegExp(types + "\/([A-Z0-9]{8})");
|
||||
var re = /(?:items|collections)\/([A-Z0-9]{8})/;
|
||||
var matches = objectURI.match(re);
|
||||
if (!matches) {
|
||||
throw ("Invalid object URI '" + objectURI + "' in Zotero.URI._getURIObject()");
|
||||
}
|
||||
var objectKey = matches[1];
|
||||
|
||||
if (libraryType == 'user') {
|
||||
return Zotero[Types].getByLibraryAndKey(null, objectKey);
|
||||
}
|
||||
|
||||
if (libraryType == 'group') {
|
||||
return Zotero[Types].getByLibraryAndKey(libraryID, objectKey);
|
||||
}
|
||||
let objectKey = matches[1];
|
||||
return {
|
||||
libraryID: libraryID,
|
||||
key: objectKey
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -847,6 +847,10 @@ Zotero.Utilities = {
|
|||
return newString;
|
||||
},
|
||||
|
||||
"capitalize": function (str) {
|
||||
return str[0].toUpperCase() + str.substr(1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces accented characters in a string with ASCII equivalents
|
||||
*
|
||||
|
|
|
@ -2079,7 +2079,7 @@ Components.utils.import("resource://gre/modules/osfile.jsm");
|
|||
//Zotero.Fulltext.purgeUnusedWords();
|
||||
yield Zotero.Items.purge();
|
||||
// DEBUG: this might not need to be permanent
|
||||
Zotero.Relations.purge();
|
||||
yield Zotero.Relations.purge();
|
||||
yield Zotero.CharacterSets.purge();
|
||||
});
|
||||
|
||||
|
@ -2679,7 +2679,7 @@ Zotero.DragDrop = {
|
|||
|
||||
getDragSource: function (dataTransfer) {
|
||||
if (!dataTransfer) {
|
||||
Zotero.debug("Drag data not available", 2);
|
||||
//Zotero.debug("Drag data not available", 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -523,13 +523,17 @@ var ZoteroPane = new function()
|
|||
function setHighlightedRowsCallback() {
|
||||
var itemIDs = ZoteroPane_Local.getSelectedItems(true);
|
||||
if (itemIDs && itemIDs.length) {
|
||||
Zotero.Collections.getCollectionsContainingItems(itemIDs, true)
|
||||
.then(function (collectionIDs) {
|
||||
if (collectionIDs) {
|
||||
ZoteroPane_Local.collectionsView.setHighlightedRows(collectionIDs);
|
||||
Zotero.Promise.coroutine(function* () {
|
||||
var collectionIDs = yield Zotero.Collections.getCollectionsContainingItems(itemIDs, true);
|
||||
var ids = collectionIDs.map(id => "C" + id);
|
||||
Zotero.debug(Zotero.Items.get(itemIDs).some(item => !item.publication));
|
||||
if (!Zotero.Items.get(itemIDs).some(item => !item.publication)) {
|
||||
ids.push("P");
|
||||
}
|
||||
})
|
||||
.done();
|
||||
if (ids.length) {
|
||||
ZoteroPane_Local.collectionsView.setHighlightedRows(ids);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1543,7 +1547,7 @@ var ZoteroPane = new function()
|
|||
var id = yield newItem.save();
|
||||
|
||||
var newItem = yield Zotero.Items.getAsync(id);
|
||||
item.clone(false, newItem, false, !Zotero.Prefs.get('groups.copyTags'));
|
||||
yield item.clone(false, newItem, false, !Zotero.Prefs.get('groups.copyTags'));
|
||||
yield newItem.save();
|
||||
|
||||
if (self.collectionsView.selectedTreeRow.isCollection() && newItem.isTopLevelItem()) {
|
||||
|
@ -1591,7 +1595,10 @@ var ZoteroPane = new function()
|
|||
)
|
||||
};
|
||||
|
||||
if (collectionTreeRow.isLibrary(true)) {
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
var prompt = toDelete;
|
||||
}
|
||||
else if (collectionTreeRow.isLibrary(true)) {
|
||||
// In library, don't prompt if meta key was pressed
|
||||
var prompt = (force && !fromMenu) ? false : toTrash;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ pane.collections.newSavedSeach = New Saved Search
|
|||
pane.collections.savedSearchName = Enter a name for this saved search:
|
||||
pane.collections.rename = Rename collection:
|
||||
pane.collections.library = My Library
|
||||
pane.collections.publications = My Publications
|
||||
pane.collections.groupLibraries = Group Libraries
|
||||
pane.collections.trash = Trash
|
||||
pane.collections.untitled = Untitled
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Why is this necessary? */
|
||||
#zotero-collections-tree treechildren::-moz-tree-image,
|
||||
#zotero-items-tree treechildren::-moz-tree-image {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#zotero-collections-pane
|
||||
{
|
||||
min-width: 150px;
|
||||
|
@ -20,17 +26,17 @@
|
|||
min-height: 5.2em;
|
||||
}
|
||||
|
||||
#zotero-collections-tree treechildren::-moz-tree-image(primary)
|
||||
{
|
||||
margin-right: 5px;
|
||||
#zotero-collections-tree treechildren::-moz-tree-row {
|
||||
height: 1.7em;
|
||||
}
|
||||
|
||||
#zotero-collections-tree #zotero-collections-sync-status-column {
|
||||
width: 35px;
|
||||
}
|
||||
/*#zotero-collections-tree treechildren::-moz-tree-separator {
|
||||
border: none;
|
||||
}*/
|
||||
|
||||
#zotero-collections-tree[hidevscroll] #zotero-collections-sync-status-column {
|
||||
width: 21px;
|
||||
#zotero-collections-tree treechildren::-moz-tree-twisty(notwisty),
|
||||
#zotero-collections-tree treechildren::-moz-tree-twisty(header) {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Set by setHighlightedRows() and getRowProperties() in collectionTreeView.js) */
|
||||
|
@ -39,11 +45,6 @@
|
|||
background: #FFFF99 !important;
|
||||
}
|
||||
|
||||
/*#zotero-collections-tree treechildren::-moz-tree-row(separator)
|
||||
{
|
||||
height: .25em;
|
||||
}*/
|
||||
|
||||
#zotero-pane splitter
|
||||
{
|
||||
border: 0;
|
||||
|
@ -60,11 +61,6 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
#zotero-items-tree treechildren::-moz-tree-image
|
||||
{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#zotero-items-tree treechildren::-moz-tree-image(hasAttachment, pie)
|
||||
{
|
||||
margin: 1px 0 0;
|
||||
|
|
BIN
chrome/skin/default/zotero/treeitem-journalArticle@2x.png
Normal file
BIN
chrome/skin/default/zotero/treeitem-journalArticle@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Loading…
Reference in a new issue