Move My Publications into My Library
Instead of My Publications being a separate library, have it be a special collection inside My Library. Top-level items can be dragged into it as before, and child items can be toggled off and on with a button in the item pane. Newly added child items won't be shown by default. For upgraders, items in the My Publications library will be moved into My Library, which might result in their being duplicated if the items weren't removed from My Library. The client will then upload those new items into My Library. The API endpoint will continue to show items in the separate My Publications library until My Publications items are added to My Library, so the profile page will continue to show them.
This commit is contained in:
parent
e311279947
commit
5ff2a59f87
28 changed files with 969 additions and 239 deletions
|
@ -33,6 +33,11 @@
|
|||
<script src="itemPane.js" type="application/javascript;version=1.8"/>
|
||||
|
||||
<vbox id="zotero-item-pane" zotero-persist="width height">
|
||||
<!-- My Publications -->
|
||||
<hbox id="zotero-item-pane-top-buttons-my-publications" class="zotero-item-pane-top-buttons" hidden="true">
|
||||
<button id="zotero-item-collection-show-hide"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Trash -->
|
||||
<hbox id="zotero-item-pane-top-buttons-trash" class="zotero-item-pane-top-buttons" hidden="true">
|
||||
<button id="zotero-item-restore-button" label="&zotero.items.menu.restoreToLibrary;"
|
||||
|
|
|
@ -318,8 +318,6 @@ Zotero_Preferences.Sync = {
|
|||
// Add default rows
|
||||
addRow(Zotero.getString("pane.collections.libraryAndFeeds"), "L" + Zotero.Libraries.userLibraryID,
|
||||
librariesToSkip.indexOf("L" + Zotero.Libraries.userLibraryID) == -1);
|
||||
addRow(Zotero.getString("pane.collections.publications"), "L" + Zotero.Libraries.publicationsLibraryID,
|
||||
librariesToSkip.indexOf("L" + Zotero.Libraries.publicationsLibraryID) == -1);
|
||||
|
||||
// Add group rows
|
||||
for (let group of groups) {
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
<checkbox id="include-notes" label="&zotero.publications.include.checkbox.notes;"
|
||||
oncommand="Zotero_Publications_Dialog.updateInclude()"/>
|
||||
<separator/>
|
||||
<description>&zotero.publications.include.adjustAtAnyTime;</description>
|
||||
<separator/>
|
||||
<checkbox id="confirm-authorship-checkbox"
|
||||
oncommand="Zotero_Publications_Dialog.updateNextButton()"/>
|
||||
</wizardpage>
|
||||
|
|
|
@ -37,7 +37,6 @@ Zotero.CollectionTreeRow = function(type, ref, level, isOpen)
|
|||
Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
|
||||
switch (this.type) {
|
||||
case 'library':
|
||||
case 'publications':
|
||||
case 'group':
|
||||
case 'feed':
|
||||
return 'L' + this.ref.libraryID;
|
||||
|
@ -54,6 +53,9 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
|
|||
case 'unfiled':
|
||||
return 'U' + this.ref.libraryID;
|
||||
|
||||
case 'publications':
|
||||
return 'P' + this.ref.libraryID;
|
||||
|
||||
case 'trash':
|
||||
return 'T' + this.ref.libraryID;
|
||||
|
||||
|
@ -73,7 +75,7 @@ Zotero.CollectionTreeRow.prototype.__defineGetter__('id', function () {
|
|||
Zotero.CollectionTreeRow.prototype.isLibrary = function (includeGlobal)
|
||||
{
|
||||
if (includeGlobal) {
|
||||
var global = ['library', 'publications', 'group', 'feed'];
|
||||
var global = ['library', 'group', 'feed'];
|
||||
return global.indexOf(this.type) != -1;
|
||||
}
|
||||
return this.type == 'library';
|
||||
|
@ -315,6 +317,9 @@ Zotero.CollectionTreeRow.prototype.getSearchObject = Zotero.Promise.coroutine(fu
|
|||
}
|
||||
includeScopeChildren = true;
|
||||
}
|
||||
else if (this.isPublications()) {
|
||||
s.addCondition('publications', 'true');
|
||||
}
|
||||
else if (this.isTrash()) {
|
||||
s.addCondition('deleted', 'true');
|
||||
}
|
||||
|
@ -383,6 +388,7 @@ Zotero.CollectionTreeRow.prototype.setTags = function (tags) {
|
|||
Zotero.CollectionTreeRow.prototype.isSearchMode = function() {
|
||||
switch (this.type) {
|
||||
case 'search':
|
||||
case 'publications':
|
||||
case 'trash':
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ Zotero.CollectionTreeView = function()
|
|||
[
|
||||
'collection',
|
||||
'search',
|
||||
'publications',
|
||||
'feed',
|
||||
'share',
|
||||
'group',
|
||||
|
@ -183,18 +182,6 @@ Zotero.CollectionTreeView.prototype.refresh = Zotero.Promise.coroutine(function*
|
|||
);
|
||||
added += yield this._expandRow(newRows, 0);
|
||||
|
||||
this._addRowToArray(newRows, new Zotero.CollectionTreeRow('separator', false), added++);
|
||||
|
||||
// Add "My Publications"
|
||||
this._addRowToArray(
|
||||
newRows,
|
||||
new Zotero.CollectionTreeRow('publications', {
|
||||
libraryID: Zotero.Libraries.publicationsLibraryID,
|
||||
treeViewID: "L" + Zotero.Libraries.publicationsLibraryID
|
||||
}),
|
||||
added++
|
||||
);
|
||||
|
||||
// TODO: Unify feed and group adding code
|
||||
|
||||
// Add groups
|
||||
|
@ -1308,12 +1295,14 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
var showDuplicates = this.hideSources.indexOf('duplicates') == -1
|
||||
&& this._virtualCollectionLibraries.duplicates[libraryID] !== false;
|
||||
var showUnfiled = this._virtualCollectionLibraries.unfiled[libraryID] !== false;
|
||||
var showPublications = libraryID == Zotero.Libraries.userLibraryID;
|
||||
var showTrash = this.hideSources.indexOf('trash') == -1;
|
||||
}
|
||||
else {
|
||||
var savedSearches = [];
|
||||
var showDuplicates = false;
|
||||
var showUnfiled = false;
|
||||
var showPublications = false;
|
||||
var showTrash = false;
|
||||
}
|
||||
|
||||
|
@ -1367,6 +1356,23 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
|
|||
newRows++;
|
||||
}
|
||||
|
||||
if (showPublications) {
|
||||
// Add "My Publications"
|
||||
this._addRowToArray(
|
||||
rows,
|
||||
new Zotero.CollectionTreeRow(
|
||||
'publications',
|
||||
{
|
||||
libraryID,
|
||||
treeViewID: "P" + libraryID
|
||||
},
|
||||
level + 1
|
||||
),
|
||||
row + 1 + newRows
|
||||
);
|
||||
newRows++
|
||||
}
|
||||
|
||||
// Duplicate items
|
||||
if (showDuplicates) {
|
||||
let d = new Zotero.Duplicates(libraryID);
|
||||
|
@ -1624,7 +1630,7 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
|
|||
continue;
|
||||
}
|
||||
|
||||
if (treeRow.isPublications() && treeRow.ref.libraryID != item.libraryID) {
|
||||
if (treeRow.isPublications()) {
|
||||
if (item.isAttachment() || item.isNote()) {
|
||||
Zotero.debug("Top-level attachments and notes cannot be added to My Publications");
|
||||
return false;
|
||||
|
@ -1790,6 +1796,16 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
|
|||
skip = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure there's at least one item that's not already in My Publications
|
||||
if (treeRow.isPublications()) {
|
||||
if (item.inPublications) {
|
||||
Zotero.debug("Item " + item.id + " already exists in My Publications");
|
||||
continue;
|
||||
}
|
||||
skip = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
Zotero.debug("Drag skipped");
|
||||
|
@ -1929,13 +1945,6 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
// Create new clone item in target library
|
||||
var newItem = item.clone(targetLibraryID, { skipTags: !options.tags });
|
||||
|
||||
// Set Rights field for My Publications
|
||||
if (options.license) {
|
||||
if (!options.keepRights || !newItem.getField('rights')) {
|
||||
newItem.setField('rights', options.licenseName);
|
||||
}
|
||||
}
|
||||
|
||||
var newItemID = yield newItem.save({
|
||||
skipSelect: true
|
||||
});
|
||||
|
@ -2121,42 +2130,34 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
copyOptions.childNotes = io.includeNotes;
|
||||
copyOptions.childFileAttachments = io.includeFiles;
|
||||
copyOptions.childLinks = true;
|
||||
copyOptions.tags = true; // TODO: add checkbox
|
||||
['keepRights', 'license', 'licenseName'].forEach(function (field) {
|
||||
copyOptions[field] = io[field];
|
||||
});
|
||||
}
|
||||
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
var newItems = [];
|
||||
var newIDs = [];
|
||||
var toMove = [];
|
||||
let newItems = [];
|
||||
let newIDs = [];
|
||||
let toMove = [];
|
||||
// TODO: support items coming from different sources?
|
||||
if (items[0].libraryID == targetLibraryID) {
|
||||
var sameLibrary = true;
|
||||
}
|
||||
else {
|
||||
var sameLibrary = false;
|
||||
}
|
||||
let sameLibrary = items[0].libraryID == targetLibraryID
|
||||
|
||||
for (let item of items) {
|
||||
if (!item.isTopLevelItem()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
newItems.push(item);
|
||||
|
||||
if (sameLibrary) {
|
||||
newIDs.push(item.id);
|
||||
toMove.push(item.id);
|
||||
}
|
||||
else {
|
||||
newItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sameLibrary) {
|
||||
var toReconcile = [];
|
||||
let toReconcile = [];
|
||||
|
||||
var newIDs = [];
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
for (let item of newItems) {
|
||||
var id = yield copyItem(item, targetLibraryID, copyOptions)
|
||||
// Standalone attachments might not get copied
|
||||
|
@ -2165,12 +2166,13 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
newIDs.push(id);
|
||||
}
|
||||
});
|
||||
|
||||
if (toReconcile.length) {
|
||||
var sourceName = Zotero.Libraries.getName(items[0].libraryID);
|
||||
var targetName = Zotero.Libraries.getName(targetLibraryID);
|
||||
let sourceName = Zotero.Libraries.getName(items[0].libraryID);
|
||||
let targetName = Zotero.Libraries.getName(targetLibraryID);
|
||||
|
||||
var io = {
|
||||
let io = {
|
||||
dataIn: {
|
||||
type: "item",
|
||||
captions: [
|
||||
|
@ -2191,25 +2193,29 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
}
|
||||
*/
|
||||
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var lastWin = wm.getMostRecentWindow("navigator:browser");
|
||||
let lastWin = wm.getMostRecentWindow("navigator:browser");
|
||||
lastWin.openDialog('chrome://zotero/content/merge.xul', '', 'chrome,modal,centerscreen', io);
|
||||
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
for (let obj of io.dataOut) {
|
||||
yield obj.ref.save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add items to target collection
|
||||
if (targetCollectionID) {
|
||||
let ids = newIDs.filter(function (itemID) {
|
||||
var item = Zotero.Items.get(itemID);
|
||||
return item.isTopLevelItem();
|
||||
});
|
||||
var collection = yield Zotero.Collections.getAsync(targetCollectionID);
|
||||
let ids = newIDs.filter(itemID => Zotero.Items.get(itemID).isTopLevelItem());
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
let collection = yield Zotero.Collections.getAsync(targetCollectionID);
|
||||
yield collection.addItems(ids);
|
||||
}.bind(this));
|
||||
}
|
||||
else if (targetTreeRow.isPublications()) {
|
||||
yield Zotero.Items.addToPublications(newItems, copyOptions);
|
||||
}
|
||||
|
||||
// If moving, remove items from source collection
|
||||
|
@ -2220,9 +2226,10 @@ Zotero.CollectionTreeView.prototype.drop = Zotero.Promise.coroutine(function* (r
|
|||
if (!sourceTreeRow || !sourceTreeRow.isCollection()) {
|
||||
throw new Error("Drag source must be a collection for move action");
|
||||
}
|
||||
yield Zotero.DB.executeTransaction(function* () {
|
||||
yield sourceTreeRow.ref.removeItems(toMove);
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (dataType == 'text/x-moz-url' || dataType == 'application/x-moz-file') {
|
||||
var targetLibraryID = targetTreeRow.ref.libraryID;
|
||||
|
@ -2332,9 +2339,7 @@ Zotero.CollectionTreeView.prototype.getCellProperties = function(row, col, prop)
|
|||
props.push("header");
|
||||
props.push("notwisty");
|
||||
}
|
||||
else if (treeRow.isPublications()) {
|
||||
props.push("notwisty");
|
||||
} else if (treeRow.ref && treeRow.ref.unreadCount) {
|
||||
else if (treeRow.ref && treeRow.ref.unreadCount) {
|
||||
props.push('unread');
|
||||
}
|
||||
|
||||
|
|
|
@ -137,11 +137,6 @@ Zotero.Collections = function() {
|
|||
|
||||
|
||||
this.getCollectionsContainingItems = function (itemIDs, asIDs) {
|
||||
// If an unreasonable number of items, don't try
|
||||
if (itemIDs.length > 100) {
|
||||
return Zotero.Promise.resolve([]);
|
||||
}
|
||||
|
||||
var sql = "SELECT collectionID FROM collections WHERE ";
|
||||
var sqlParams = [];
|
||||
for (let id of itemIDs) {
|
||||
|
|
|
@ -374,6 +374,7 @@ Zotero.Item.prototype._parseRowData = function(row) {
|
|||
// Boolean
|
||||
case 'synced':
|
||||
case 'deleted':
|
||||
case 'inPublications':
|
||||
val = !!val;
|
||||
break;
|
||||
|
||||
|
@ -1133,9 +1134,11 @@ Zotero.Item.prototype.removeCreator = function(orderIndex, allowMissing) {
|
|||
}
|
||||
|
||||
|
||||
// Define 'deleted' property (and any others that follow the same pattern in the future)
|
||||
for (let name of ['deleted']) {
|
||||
// Define boolean properties
|
||||
for (let name of ['deleted', 'inPublications']) {
|
||||
let prop = '_' + name;
|
||||
// Fix for https://bugzilla.mozilla.org/show_bug.cgi?id=449811 (Fixed in Fx51)
|
||||
let tmpName = name;
|
||||
|
||||
Zotero.defineProperty(Zotero.Item.prototype, name, {
|
||||
get: function() {
|
||||
|
@ -1151,12 +1154,12 @@ for (let name of ['deleted']) {
|
|||
val = !!val;
|
||||
|
||||
if (this[prop] == val) {
|
||||
Zotero.debug(Zotero.Utilities.capitalize(name)
|
||||
Zotero.debug(Zotero.Utilities.capitalize(tmpName)
|
||||
+ " state hasn't changed for item " + this.id);
|
||||
return;
|
||||
}
|
||||
this._markFieldChange(name, !!this[prop]);
|
||||
this._changed[name] = true;
|
||||
this._markFieldChange(tmpName, !!this[prop]);
|
||||
this._changed[tmpName] = true;
|
||||
this[prop] = val;
|
||||
}
|
||||
});
|
||||
|
@ -1510,17 +1513,13 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
|||
}
|
||||
}
|
||||
|
||||
if (libraryType == 'publications' && !this.isRegularItem() && !parentItemID) {
|
||||
if (this._inPublications && !this.isRegularItem() && !parentItemID) {
|
||||
throw new Error("Top-level attachments and notes cannot be added to My Publications");
|
||||
}
|
||||
|
||||
// Trashed status
|
||||
if (this._changed.deleted) {
|
||||
if (this._deleted) {
|
||||
if (libraryType == 'publications') {
|
||||
throw new Error("Items in My Publications cannot be moved to trash");
|
||||
}
|
||||
|
||||
sql = "REPLACE INTO deletedItems (itemID) VALUES (?)";
|
||||
}
|
||||
else {
|
||||
|
@ -1554,6 +1553,16 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
|||
}
|
||||
}
|
||||
|
||||
if (this._changed.inPublications) {
|
||||
if (this._inPublications) {
|
||||
sql = "INSERT OR IGNORE INTO publicationsItems (itemID) VALUES (?)";
|
||||
}
|
||||
else {
|
||||
sql = "DELETE FROM publicationsItems WHERE itemID=?";
|
||||
}
|
||||
yield Zotero.DB.queryAsync(sql, itemID);
|
||||
}
|
||||
|
||||
// Note
|
||||
if ((isNew && this.isNote()) || this._changed.note) {
|
||||
if (!isNew) {
|
||||
|
@ -3624,6 +3633,28 @@ Zotero.DataObject.prototype.setDeleted = Zotero.Promise.coroutine(function* (del
|
|||
});
|
||||
|
||||
|
||||
/**
|
||||
* Update item publications state without marking as changed or modifying DB
|
||||
*
|
||||
* This is used by Zotero.Items.addToPublications()/removeFromPublications()
|
||||
*
|
||||
* Database state must be set separately!
|
||||
*
|
||||
* @param {Boolean} inPublications
|
||||
*/
|
||||
Zotero.DataObject.prototype.setPublications = Zotero.Promise.coroutine(function* (inPublications) {
|
||||
if (!this.id) {
|
||||
throw new Error("Cannot update publications state of unsaved item");
|
||||
}
|
||||
|
||||
this._inPublications = !!inPublications;
|
||||
|
||||
if (this._changed.inPublications) {
|
||||
delete this._changed.inPublications;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Zotero.Item.prototype.getImageSrc = function() {
|
||||
var itemType = Zotero.ItemTypes.getName(this.itemTypeID);
|
||||
if (itemType == 'attachment') {
|
||||
|
@ -4086,7 +4117,8 @@ Zotero.Item.prototype.fromJSON = function (json) {
|
|||
break;
|
||||
|
||||
case 'deleted':
|
||||
this.deleted = !!val;
|
||||
case 'inPublications':
|
||||
this[field] = !!val;
|
||||
break;
|
||||
|
||||
case 'creators':
|
||||
|
@ -4262,15 +4294,21 @@ Zotero.Item.prototype.toJSON = function (options = {}) {
|
|||
}.bind(this));
|
||||
}
|
||||
|
||||
// Relations
|
||||
obj.relations = this.getRelations()
|
||||
// My Publications
|
||||
if (this._inPublications || mode == 'full') {
|
||||
obj.inPublications = this._inPublications;
|
||||
}
|
||||
|
||||
// Deleted
|
||||
let deleted = this.deleted;
|
||||
if (deleted || mode == 'full') {
|
||||
// Match what APIv3 returns, though it would be good to change this
|
||||
obj.deleted = deleted ? 1 : 0;
|
||||
}
|
||||
|
||||
// Relations
|
||||
obj.relations = this.getRelations()
|
||||
|
||||
if (obj.accessDate) obj.accessDate = Zotero.Date.sqlToISO8601(obj.accessDate);
|
||||
|
||||
if (this.dateAdded) {
|
||||
|
|
|
@ -50,6 +50,7 @@ Zotero.Items = function() {
|
|||
sortCreator: _getSortCreatorSQL(),
|
||||
|
||||
deleted: "DI.itemID IS NOT NULL AS deleted",
|
||||
inPublications: "PI.itemID IS NOT NULL AS inPublications",
|
||||
|
||||
numNotes: "(SELECT COUNT(*) FROM itemNotes INo "
|
||||
+ "WHERE parentItemID=O.itemID AND "
|
||||
|
@ -99,6 +100,7 @@ Zotero.Items = function() {
|
|||
+ "LEFT JOIN itemNotes INo ON (O.itemID=INo.itemID) "
|
||||
+ "LEFT JOIN items INoP ON (INo.parentItemID=INoP.itemID) "
|
||||
+ "LEFT JOIN deletedItems DI ON (O.itemID=DI.itemID) "
|
||||
+ "LEFT JOIN publicationsItems PI ON (O.itemID=PI.itemID) "
|
||||
+ "LEFT JOIN charsets CS ON (IA.charsetID=CS.charsetID)";
|
||||
|
||||
this._relationsTable = "itemRelations";
|
||||
|
@ -976,6 +978,107 @@ Zotero.Items = function() {
|
|||
}
|
||||
|
||||
|
||||
this.addToPublications = function (items, options = {}) {
|
||||
if (!items.length) return;
|
||||
|
||||
return Zotero.DB.executeTransaction(function* () {
|
||||
var timestamp = Zotero.DB.transactionTimestamp;
|
||||
|
||||
var allItems = [...items];
|
||||
|
||||
if (options.license) {
|
||||
for (let item of items) {
|
||||
if (!options.keepRights || !item.getField('rights')) {
|
||||
item.setField('rights', options.licenseName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.childNotes) {
|
||||
for (let item of items) {
|
||||
item.getNotes().forEach(id => allItems.push(Zotero.Items.get(id)));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.childFileAttachments || options.childLinks) {
|
||||
for (let item of items) {
|
||||
item.getAttachments().forEach(id => {
|
||||
var attachment = Zotero.Items.get(id);
|
||||
var linkMode = attachment.attachmentLinkMode;
|
||||
|
||||
if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
Zotero.debug("Skipping child linked file attachment on drag");
|
||||
return;
|
||||
}
|
||||
if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_URL) {
|
||||
if (!options.childLinks) {
|
||||
Zotero.debug("Skipping child link attachment on drag");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!options.childFileAttachments) {
|
||||
Zotero.debug("Skipping child file attachment on drag");
|
||||
return;
|
||||
}
|
||||
allItems.push(attachment);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
yield Zotero.Utilities.Internal.forEachChunkAsync(allItems, 250, Zotero.Promise.coroutine(function* (chunk) {
|
||||
for (let item of chunk) {
|
||||
item.setPublications(true);
|
||||
item.synced = false;
|
||||
}
|
||||
let ids = chunk.map(item => item.id);
|
||||
yield Zotero.DB.queryAsync(
|
||||
`UPDATE items SET synced=0, clientDateModified=? WHERE itemID IN (${ids.join(", ")})`,
|
||||
timestamp
|
||||
);
|
||||
yield Zotero.DB.queryAsync(
|
||||
`INSERT OR IGNORE INTO publicationsItems VALUES (${ids.join("), (")})`
|
||||
);
|
||||
}.bind(this)));
|
||||
Zotero.Notifier.queue('modify', 'item', allItems.map(item => item.id));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
this.removeFromPublications = function (items) {
|
||||
return Zotero.DB.executeTransaction(function* () {
|
||||
let allItems = [];
|
||||
for (let item of items) {
|
||||
if (!item.inPublications) {
|
||||
throw new Error(`Item ${item.libraryKey} is not in My Publications`);
|
||||
}
|
||||
|
||||
// Remove all child items too
|
||||
if (item.isRegularItem()) {
|
||||
allItems.push(...this.get(item.getNotes(true).concat(item.getAttachments(true))));
|
||||
}
|
||||
|
||||
allItems.push(item);
|
||||
}
|
||||
|
||||
allItems.forEach(item => {
|
||||
item.setPublications(false);
|
||||
item.synced = false;
|
||||
});
|
||||
|
||||
var timestamp = Zotero.DB.transactionTimestamp;
|
||||
yield Zotero.Utilities.Internal.forEachChunkAsync(allItems, 250, Zotero.Promise.coroutine(function* (chunk) {
|
||||
let idStr = chunk.map(item => item.id).join(", ");
|
||||
yield Zotero.DB.queryAsync(
|
||||
`UPDATE items SET synced=0, clientDateModified=? WHERE itemID IN (${idStr})`,
|
||||
timestamp
|
||||
);
|
||||
yield Zotero.DB.queryAsync(`DELETE FROM publicationsItems WHERE itemID IN (${idStr})`);
|
||||
}.bind(this)));
|
||||
Zotero.Notifier.queue('modify', 'item', items.map(item => item.id));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Purge unused data values
|
||||
*/
|
||||
|
|
|
@ -40,16 +40,6 @@ Zotero.Libraries = new function () {
|
|||
}
|
||||
})
|
||||
|
||||
let _publicationsLibraryID;
|
||||
Zotero.defineProperty(this, 'publicationsLibraryID', {
|
||||
get: function() {
|
||||
if (_publicationsLibraryID === undefined) {
|
||||
throw new Error("Library data not yet loaded");
|
||||
}
|
||||
return _publicationsLibraryID;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Manage cache
|
||||
*/
|
||||
|
@ -105,7 +95,6 @@ Zotero.Libraries = new function () {
|
|||
let library;
|
||||
switch (row._libraryType) {
|
||||
case 'user':
|
||||
case 'publications':
|
||||
library = new Zotero.Library();
|
||||
library._loadDataFromRow(row); // Does not call save()
|
||||
break;
|
||||
|
@ -116,9 +105,6 @@ Zotero.Libraries = new function () {
|
|||
if (library.libraryType == 'user') {
|
||||
_userLibraryID = library.libraryID;
|
||||
}
|
||||
else if (library.libraryType == 'publications') {
|
||||
_publicationsLibraryID = library.libraryID;
|
||||
}
|
||||
|
||||
this._addToCache(newCaches.library, library);
|
||||
}
|
||||
|
@ -169,12 +155,10 @@ Zotero.Libraries = new function () {
|
|||
if (!this._cache) throw new Error("Zotero.Libraries cache is not initialized");
|
||||
var libraries = Object.keys(this._cache).map(v => Zotero.Libraries.get(parseInt(v)));
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
// Sort My Library, My Publications, then others by name
|
||||
// Sort My Library, then others by name
|
||||
libraries.sort(function (a, b) {
|
||||
if (a.libraryID == _userLibraryID) return -1;
|
||||
if (b.libraryID == _userLibraryID) return 1;
|
||||
if (a.libraryID == _publicationsLibraryID) return -1;
|
||||
if (b.libraryID == _publicationsLibraryID) return 1;
|
||||
return collation.compareString(1, a.name, b.name);
|
||||
}.bind(this))
|
||||
return libraries;
|
||||
|
|
|
@ -103,12 +103,12 @@ Zotero.defineProperty(Zotero.Library.prototype, '_childObjectTypes', {
|
|||
|
||||
// Valid library types
|
||||
Zotero.defineProperty(Zotero.Library.prototype, 'libraryTypes', {
|
||||
value: Object.freeze(['user', 'publications'])
|
||||
value: Object.freeze(['user'])
|
||||
});
|
||||
|
||||
// Immutable libraries
|
||||
Zotero.defineProperty(Zotero.Library.prototype, 'fixedLibraries', {
|
||||
value: Object.freeze(['user', 'publications'])
|
||||
value: Object.freeze(['user'])
|
||||
});
|
||||
|
||||
Zotero.defineProperty(Zotero.Library.prototype, 'libraryID', {
|
||||
|
@ -136,7 +136,6 @@ Zotero.defineProperty(Zotero.Library.prototype, 'libraryTypeID', {
|
|||
get: function () {
|
||||
switch (this._libraryType) {
|
||||
case 'user':
|
||||
case 'publications':
|
||||
return Zotero.Users.getCurrentUserID();
|
||||
|
||||
case 'group':
|
||||
|
@ -170,10 +169,6 @@ Zotero.defineProperty(Zotero.Library.prototype, 'name', {
|
|||
return Zotero.getString('pane.collections.library');
|
||||
}
|
||||
|
||||
if (this._libraryType == 'publications') {
|
||||
return Zotero.getString('pane.collections.publications');
|
||||
}
|
||||
|
||||
throw new Error('Unhandled library type "' + this._libraryType + '"');
|
||||
}
|
||||
});
|
||||
|
@ -254,7 +249,7 @@ Zotero.Library.prototype._set = function(prop, val) {
|
|||
|
||||
case '_libraryEditable':
|
||||
case '_libraryFilesEditable':
|
||||
if (['user', 'publications'].indexOf(this._libraryType) != -1) {
|
||||
if (['user'].indexOf(this._libraryType) != -1) {
|
||||
throw new Error('Cannot change ' + prop + ' for ' + this._libraryType + ' library');
|
||||
}
|
||||
val = !!val;
|
||||
|
@ -303,7 +298,7 @@ Zotero.Library.prototype._set = function(prop, val) {
|
|||
break;
|
||||
|
||||
case '_libraryArchived':
|
||||
if (['user', 'publications', 'feeds'].indexOf(this._libraryType) != -1) {
|
||||
if (['user', 'feeds'].indexOf(this._libraryType) != -1) {
|
||||
throw new Error('Cannot change ' + prop + ' for ' + this._libraryType + ' library');
|
||||
}
|
||||
if (val && this._libraryEditable) {
|
||||
|
|
|
@ -989,6 +989,10 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
|
|||
var unfiled = condition.operator == 'true';
|
||||
continue;
|
||||
|
||||
case 'publications':
|
||||
var publications = condition.operator == 'true';
|
||||
continue;
|
||||
|
||||
// Search subcollections
|
||||
case 'recursive':
|
||||
var recursive = condition.operator == 'true';
|
||||
|
@ -1045,6 +1049,10 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
|
|||
+ ")";
|
||||
}
|
||||
|
||||
if (publications) {
|
||||
sql += " AND (itemID IN (SELECT itemID FROM publicationsItems))";
|
||||
}
|
||||
|
||||
// Limit to library search belongs to
|
||||
//
|
||||
// This is equivalent to adding libraryID as a search condition,
|
||||
|
|
|
@ -99,6 +99,14 @@ Zotero.SearchConditions = new function(){
|
|||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'publications',
|
||||
operators: {
|
||||
true: true,
|
||||
false: true
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'includeParentsAndChildren',
|
||||
operators: {
|
||||
|
|
|
@ -439,6 +439,11 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f
|
|||
this.selection.selectEventsSuppressed = false;
|
||||
}
|
||||
|
||||
// Clear My Publications intro text on a refresh with items
|
||||
if (this.collectionTreeRow.isPublications() && this.rowCount) {
|
||||
this._ownerDocument.defaultView.ZoteroPane_Local.clearItemsPaneMessage();
|
||||
}
|
||||
|
||||
yield this.runListeners('refresh');
|
||||
|
||||
setTimeout(function () {
|
||||
|
@ -557,12 +562,6 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
refreshed = true;
|
||||
}
|
||||
}
|
||||
else if (type == 'publications') {
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
yield this.refresh();
|
||||
refreshed = true;
|
||||
}
|
||||
}
|
||||
// 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._rowMap[ids[0]];
|
||||
|
@ -667,9 +666,10 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
delete this._cellTextCache[id];
|
||||
}
|
||||
|
||||
// If trash or saved search, just re-run search
|
||||
if (collectionTreeRow.isTrash() || collectionTreeRow.isSearch())
|
||||
{
|
||||
// If saved search, publications, or trash, just re-run search
|
||||
if (collectionTreeRow.isSearch()
|
||||
|| collectionTreeRow.isPublications()
|
||||
|| collectionTreeRow.isTrash()) {
|
||||
yield this.refresh();
|
||||
refreshed = true;
|
||||
madeChanges = true;
|
||||
|
@ -789,7 +789,10 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
|||
let items = Zotero.Items.get(ids);
|
||||
|
||||
// In some modes, just re-run search
|
||||
if (collectionTreeRow.isSearch() || collectionTreeRow.isTrash() || collectionTreeRow.isUnfiled()) {
|
||||
if (collectionTreeRow.isSearch()
|
||||
|| collectionTreeRow.isPublications()
|
||||
|| collectionTreeRow.isTrash()
|
||||
|| collectionTreeRow.isUnfiled()) {
|
||||
yield this.refresh();
|
||||
refreshed = true;
|
||||
madeChanges = true;
|
||||
|
@ -1887,7 +1890,7 @@ Zotero.ItemTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(functio
|
|||
if (collectionTreeRow.isBucket()) {
|
||||
collectionTreeRow.ref.deleteItems(ids);
|
||||
}
|
||||
else if (collectionTreeRow.isTrash() || collectionTreeRow.isPublications()) {
|
||||
if (collectionTreeRow.isTrash()) {
|
||||
yield Zotero.Items.erase(ids);
|
||||
}
|
||||
else if (collectionTreeRow.isLibrary(true) || force) {
|
||||
|
@ -1898,6 +1901,10 @@ Zotero.ItemTreeView.prototype.deleteSelection = Zotero.Promise.coroutine(functio
|
|||
yield collectionTreeRow.ref.removeItems(ids);
|
||||
});
|
||||
}
|
||||
else if (collectionTreeRow.isPublications()) {
|
||||
yield Zotero.Items.removeFromPublications(ids.map(id => Zotero.Items.get(id)));
|
||||
}
|
||||
|
||||
//this._treebox.endUpdateBatch();
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Zotero.Notifier = new function(){
|
|||
var _observers = {};
|
||||
var _types = [
|
||||
'collection', 'search', 'share', 'share-items', 'item', 'file',
|
||||
'collection-item', 'item-tag', 'tag', 'setting', 'group', 'trash', 'publications',
|
||||
'collection-item', 'item-tag', 'tag', 'setting', 'group', 'trash',
|
||||
'bucket', 'relation', 'feed', 'feedItem', 'sync', 'api-key'
|
||||
];
|
||||
var _inTransaction;
|
||||
|
|
|
@ -34,7 +34,7 @@ Zotero.Schema = new function(){
|
|||
var _dbVersions = [];
|
||||
var _schemaVersions = [];
|
||||
// Update when adding _updateCompatibility() line to schema update step
|
||||
var _maxCompatibility = 4;
|
||||
var _maxCompatibility = 5;
|
||||
var _repositoryTimer;
|
||||
var _remoteUpdateInProgress = false, _localUpdateInProgress = false;
|
||||
|
||||
|
@ -1356,8 +1356,7 @@ Zotero.Schema = new function(){
|
|||
|
||||
var sql = "INSERT INTO libraries (libraryID, type, editable, filesEditable) "
|
||||
+ "VALUES "
|
||||
+ "(?, 'user', 1, 1), "
|
||||
+ "(4, 'publications', 1, 1)"
|
||||
+ "(?, 'user', 1, 1)";
|
||||
yield Zotero.DB.queryAsync(sql, userLibraryID);
|
||||
|
||||
/*if (!Zotero.Schema.skipDefaultData) {
|
||||
|
@ -2370,6 +2369,28 @@ Zotero.Schema = new function(){
|
|||
yield Zotero.DB.queryAsync("UPDATE itemRelations SET object='http://zotero.org/users/' || ? || SUBSTR(object, 39) WHERE object LIKE ?", [userID, 'http://zotero.org/users/local/%']);
|
||||
}
|
||||
}
|
||||
|
||||
else if (i == 93) {
|
||||
yield _updateCompatibility(5);
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE publicationsItems (\n itemID INTEGER PRIMARY KEY\n);");
|
||||
yield Zotero.DB.queryAsync("INSERT INTO publicationsItems SELECT itemID FROM items WHERE libraryID=4");
|
||||
yield Zotero.DB.queryAsync("UPDATE OR IGNORE items SET libraryID=1, synced=0 WHERE libraryID=4");
|
||||
yield Zotero.DB.queryAsync("DELETE FROM itemRelations WHERE object LIKE ? AND object LIKE ?", ['http://zotero.org/users/%', '%/publications/items%']);
|
||||
yield Zotero.DB.queryAsync("DELETE FROM libraries WHERE libraryID=4");
|
||||
|
||||
let rows = yield Zotero.DB.queryAsync("SELECT itemID, data FROM syncCache JOIN items USING (libraryID, key, version) WHERE syncObjectTypeID=3");
|
||||
let ids = [];
|
||||
for (let row of rows) {
|
||||
let json = JSON.parse(row.data);
|
||||
if (json.data && json.data.inPublications) {
|
||||
ids.push(row.itemID);
|
||||
}
|
||||
}
|
||||
if (ids.length) {
|
||||
yield Zotero.DB.queryAsync("INSERT INTO publicationsItems (itemID) VALUES "
|
||||
+ ids.map(id => `(${id})`).join(', '));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield _updateDBVersion('userdata', toVersion);
|
||||
|
|
|
@ -319,7 +319,7 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
|||
|
||||
if (syncAllLibraries) {
|
||||
if (access.user && access.user.library) {
|
||||
libraries = [Zotero.Libraries.userLibraryID, Zotero.Libraries.publicationsLibraryID];
|
||||
libraries = [Zotero.Libraries.userLibraryID];
|
||||
// If syncing all libraries, remove skipped libraries
|
||||
libraries = Zotero.Utilities.arrayDiff(
|
||||
libraries, Zotero.Sync.Data.Local.getSkippedLibraries()
|
||||
|
@ -330,7 +330,7 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
|||
// Check access to specified libraries
|
||||
for (let libraryID of libraries) {
|
||||
let type = Zotero.Libraries.get(libraryID).libraryType;
|
||||
if (type == 'user' || type == 'publications') {
|
||||
if (type == 'user') {
|
||||
if (!access.user || !access.user.library) {
|
||||
// TODO: Alert
|
||||
throw new Error("Key does not have access to library " + libraryID);
|
||||
|
|
|
@ -546,20 +546,24 @@ var ZoteroPane = new function()
|
|||
*/
|
||||
function setHighlightedRowsCallback() {
|
||||
var itemIDs = ZoteroPane_Local.getSelectedItems(true);
|
||||
if (itemIDs && itemIDs.length) {
|
||||
// If no items or an unreasonable number, don't try
|
||||
if (!itemIDs || !itemIDs.length || itemIDs.length > 100) return;
|
||||
|
||||
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");
|
||||
var userLibraryID = Zotero.Libraries.userLibraryID;
|
||||
var allInPublications = Zotero.Items.get(itemIDs).every((item) => {
|
||||
return item.libraryID == userLibraryID && item.inPublications;
|
||||
})
|
||||
if (allInPublications) {
|
||||
ids.push("P" + Zotero.Libraries.userLibraryID);
|
||||
}
|
||||
if (ids.length) {
|
||||
ZoteroPane_Local.collectionsView.setHighlightedRows(ids);
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleKeyPress(event) {
|
||||
|
@ -1233,6 +1237,9 @@ var ZoteroPane = new function()
|
|||
this._updateToolbarIconsForRow(collectionTreeRow);
|
||||
|
||||
this.itemsView = new Zotero.ItemTreeView(collectionTreeRow);
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
this.itemsView.expandAll = true;
|
||||
}
|
||||
this.itemsView.onError = function () {
|
||||
// Don't reload last folder, in case that's the problem
|
||||
Zotero.Prefs.clear('lastViewedFolder');
|
||||
|
@ -1391,10 +1398,15 @@ var ZoteroPane = new function()
|
|||
return false;
|
||||
}
|
||||
|
||||
var selectedItems = this.itemsView.getSelectedItems();
|
||||
|
||||
// Display buttons at top of item pane depending on context. This needs to run even if the
|
||||
// selection hasn't changed, because the selected items might have been modified.
|
||||
this.updateItemPaneButtons(selectedItems);
|
||||
|
||||
// Check if selection has actually changed. The onselect event that calls this
|
||||
// can be called in various situations where the selection didn't actually change,
|
||||
// such as whenever selectEventsSuppressed is set to false.
|
||||
var selectedItems = this.itemsView.getSelectedItems();
|
||||
var ids = selectedItems.map(item => item.id);
|
||||
ids.sort();
|
||||
if (ids.length && Zotero.Utilities.arrayEquals(_lastSelectedItems, ids)) {
|
||||
|
@ -1402,20 +1414,6 @@ var ZoteroPane = new function()
|
|||
}
|
||||
_lastSelectedItems = ids;
|
||||
|
||||
// Display restore/delete buttons depending on context
|
||||
if (this.itemsView.selection.count) {
|
||||
document.getElementById('zotero-item-pane-top-buttons-trash').hidden
|
||||
= !this.getCollectionTreeRow().isTrash()
|
||||
|| _nonDeletedItemsSelected(this.itemsView);
|
||||
|
||||
document.getElementById('zotero-item-pane-top-buttons-feed').hidden
|
||||
= !this.getCollectionTreeRow().isFeed()
|
||||
}
|
||||
else {
|
||||
document.getElementById('zotero-item-pane-top-buttons-trash').hidden = true;
|
||||
document.getElementById('zotero-item-pane-top-buttons-feed').hidden = true;
|
||||
}
|
||||
|
||||
var tabs = document.getElementById('zotero-view-tabbox');
|
||||
|
||||
// save note when switching from a note
|
||||
|
@ -1595,33 +1593,47 @@ var ZoteroPane = new function()
|
|||
|
||||
|
||||
/**
|
||||
* Check if any selected items in the passed (trash) treeview are not deleted
|
||||
* Display buttons at top of item pane depending on context
|
||||
*
|
||||
* @param {nsITreeView}
|
||||
* @return {Boolean}
|
||||
* @param {Zotero.Item[]}
|
||||
*/
|
||||
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++) {
|
||||
let itemRow = itemsView.getRow(j);
|
||||
|
||||
// DEBUG: Not sure how this is possible, but it was happening while switching
|
||||
// to an item in the trash in a collapsed library from another library
|
||||
if (!itemRow) {
|
||||
Zotero.debug("Item row " + j + " not found in _nonDeletedItemsSelected()", 2);
|
||||
continue;
|
||||
this.updateItemPaneButtons = function (selectedItems) {
|
||||
if (!selectedItems.length) {
|
||||
document.querySelectorAll('.zotero-item-pane-top-buttons').forEach(x => x.hidden = true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itemRow.ref.deleted) {
|
||||
return true;
|
||||
// My Publications buttons
|
||||
let isPublications = this.getCollectionTreeRow().isPublications();
|
||||
let myPublicationsButtons = document.getElementById('zotero-item-pane-top-buttons-my-publications');
|
||||
let regularItemsSelected = selectedItems.some(item => item.isRegularItem());
|
||||
let myPublicationsShown = isPublications && !regularItemsSelected;
|
||||
myPublicationsButtons.hidden = !myPublicationsShown;
|
||||
if (myPublicationsShown) {
|
||||
let button = myPublicationsButtons.firstChild;
|
||||
let hiddenItemsSelected = selectedItems.some(item => !item.inPublications);
|
||||
let str, onclick;
|
||||
if (hiddenItemsSelected) {
|
||||
str = 'showInMyPublications';
|
||||
onclick = () => Zotero.Items.addToPublications(selectedItems);
|
||||
}
|
||||
else {
|
||||
str = 'hideFromMyPublications';
|
||||
onclick = () => Zotero.Items.removeFromPublications(selectedItems);
|
||||
}
|
||||
button.label = Zotero.getString('pane.item.' + str);
|
||||
button.onclick = onclick;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trash button
|
||||
let nonDeletedItemsSelected = selectedItems.some(item => !item.deleted);
|
||||
document.getElementById('zotero-item-pane-top-buttons-trash').hidden
|
||||
= !this.getCollectionTreeRow().isTrash() || nonDeletedItemsSelected;
|
||||
|
||||
// Feed buttons
|
||||
document.getElementById('zotero-item-pane-top-buttons-feed').hidden
|
||||
= !this.getCollectionTreeRow().isFeed()
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1805,7 +1817,13 @@ var ZoteroPane = new function()
|
|||
};
|
||||
|
||||
if (collectionTreeRow.isPublications()) {
|
||||
var prompt = toDelete;
|
||||
let toRemoveFromPublications = {
|
||||
title: Zotero.getString('pane.items.removeFromPublications.title'),
|
||||
text: Zotero.getString(
|
||||
'pane.items.removeFromPublications' + (this.itemsView.selection.count > 1 ? '.multiple' : '')
|
||||
)
|
||||
};
|
||||
var prompt = force ? toTrash : toRemoveFromPublications;
|
||||
}
|
||||
else if (collectionTreeRow.isLibrary(true)) {
|
||||
// In library, don't prompt if meta key was pressed
|
||||
|
@ -2558,8 +2576,6 @@ var ZoteroPane = new function()
|
|||
}
|
||||
else if (collectionTreeRow.isPublications()) {
|
||||
show = [
|
||||
'sync',
|
||||
'sep1',
|
||||
'exportFile'
|
||||
];
|
||||
}
|
||||
|
@ -2647,7 +2663,7 @@ var ZoteroPane = new function()
|
|||
'sep2',
|
||||
'toggleRead',
|
||||
'duplicateItem',
|
||||
'deleteItem',
|
||||
'removeItems',
|
||||
'restoreToLibrary',
|
||||
'moveToTrash',
|
||||
'deleteFromLibrary',
|
||||
|
@ -2688,9 +2704,6 @@ var ZoteroPane = new function()
|
|||
show.push(m.deleteFromLibrary);
|
||||
show.push(m.restoreToLibrary);
|
||||
}
|
||||
else if (collectionTreeRow.isPublications()) {
|
||||
show.push(m.deleteFromLibrary);
|
||||
}
|
||||
else if (!collectionTreeRow.isFeed()) {
|
||||
show.push(m.moveToTrash);
|
||||
}
|
||||
|
@ -2852,7 +2865,7 @@ var ZoteroPane = new function()
|
|||
menu.childNodes[m.toggleRead].setAttribute('label', Zotero.getString('pane.item.markAsRead'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (!collectionTreeRow.isPublications()) {
|
||||
show.push(m.duplicateItem);
|
||||
}
|
||||
}
|
||||
|
@ -2877,14 +2890,15 @@ var ZoteroPane = new function()
|
|||
show.push(m.showInLibrary, m.sep1);
|
||||
}
|
||||
|
||||
disable.push(m.showInLibrary, m.duplicateItem, m.deleteItem,
|
||||
disable.push(m.showInLibrary, m.duplicateItem, m.removeItems,
|
||||
m.moveToTrash, m.deleteFromLibrary, m.exportItems, m.createBib, m.loadReport);
|
||||
}
|
||||
|
||||
if ((!collectionTreeRow.editable || collectionTreeRow.isPublications()) && !collectionTreeRow.isFeed()) {
|
||||
for (let i in m) {
|
||||
// Still allow export/bib/report/read for non-editable views
|
||||
// Still allow some options for non-editable views
|
||||
switch (i) {
|
||||
case 'showInLibrary':
|
||||
case 'exportItems':
|
||||
case 'createBib':
|
||||
case 'loadReport':
|
||||
|
@ -2901,7 +2915,8 @@ var ZoteroPane = new function()
|
|||
else if (collectionTreeRow.isPublications()) {
|
||||
switch (i) {
|
||||
case 'addNote':
|
||||
case 'deleteFromLibrary':
|
||||
case 'removeItems':
|
||||
case 'moveToTrash':
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -2910,10 +2925,13 @@ var ZoteroPane = new function()
|
|||
}
|
||||
|
||||
// Remove from collection
|
||||
if (collectionTreeRow.isCollection() && !(item && !item.isTopLevelItem()))
|
||||
{
|
||||
menu.childNodes[m.deleteItem].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
|
||||
show.push(m.deleteItem);
|
||||
if (collectionTreeRow.isCollection() && (!item || item.isTopLevelItem())) {
|
||||
menu.childNodes[m.removeItems].setAttribute('label', Zotero.getString('pane.items.menu.remove' + multiple));
|
||||
show.push(m.removeItems);
|
||||
}
|
||||
else if (collectionTreeRow.isPublications()) {
|
||||
menu.childNodes[m.removeItems].setAttribute('label', Zotero.getString('pane.items.menu.removeFromPublications' + multiple));
|
||||
show.push(m.removeItems);
|
||||
}
|
||||
|
||||
// Set labels, plural if necessary
|
||||
|
|
|
@ -295,7 +295,7 @@
|
|||
<menuseparator/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-toggle-read-item" oncommand="ZoteroPane_Local.toggleSelectedItemsRead();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-duplicate-item" label="&zotero.items.menu.duplicateItem;" oncommand="ZoteroPane_Local.duplicateSelectedItem().done();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-delete-collection" oncommand="ZoteroPane_Local.deleteSelectedItems();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-remove-items" oncommand="ZoteroPane_Local.deleteSelectedItems();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-restore-to-library" label="&zotero.items.menu.restoreToLibrary;" oncommand="ZoteroPane_Local.restoreSelectedItems();"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-move-to-trash" oncommand="ZoteroPane_Local.deleteSelectedItems(true, true);"/>
|
||||
<menuitem class="menuitem-iconic zotero-menuitem-delete-from-lib" oncommand="ZoteroPane_Local.deleteSelectedItems(false, true)"/>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<!ENTITY zotero.publications.intro "Items you add to My Publications will be shown on your profile page on zotero.org. If you choose to include attached files, they will be made publicly available under the license you specify. Only add work you yourself have created, and only include files if you have the rights to distribute them and wish to do so.">
|
||||
<!ENTITY zotero.publications.include.checkbox.files "Include files">
|
||||
<!ENTITY zotero.publications.include.checkbox.notes "Include notes">
|
||||
<!ENTITY zotero.publications.include.adjustAtAnyTime "You can adjust what to show at any time from the My Publications collection.">
|
||||
|
||||
<!ENTITY zotero.publications.sharing.title "Choose how your work may be shared">
|
||||
<!ENTITY zotero.publications.sharing.text "You can reserve all rights to your work, license it under a Creative Commons license, or dedicate it to the public domain. In all cases, the work will be made publicly available via zotero.org.">
|
||||
|
|
|
@ -255,8 +255,13 @@ pane.items.delete.multiple = Are you sure you want to delete the selected items
|
|||
pane.items.remove.title = Remove from Collection
|
||||
pane.items.remove = Are you sure you want to remove the selected item from this collection?
|
||||
pane.items.remove.multiple = Are you sure you want to remove the selected items from this collection?
|
||||
pane.items.removeFromPublications.title = Remove from My Publications
|
||||
pane.items.removeFromPublications = Are you sure you want to remove the selected item from My Publications?
|
||||
pane.items.removeFromPublications.multiple = Are you sure you want to remove the selected items from My Publications?
|
||||
pane.items.menu.remove = Remove Item from Collection…
|
||||
pane.items.menu.remove.multiple = Remove Items from Collection…
|
||||
pane.items.menu.removeFromPublications = Remove Item from My Publications…
|
||||
pane.items.menu.removeFromPublications.multiple = Remove Items from My Publications…
|
||||
pane.items.menu.moveToTrash = Move Item to Trash…
|
||||
pane.items.menu.moveToTrash.multiple = Move Items to Trash…
|
||||
pane.items.menu.delete = Delete Item…
|
||||
|
@ -301,6 +306,8 @@ pane.item.duplicates.onlySameItemType = Merged items must all be of the same it
|
|||
pane.item.markAsRead = Mark As Read
|
||||
pane.item.markAsUnread = Mark As Unread
|
||||
pane.item.addTo = Add to “%S”
|
||||
pane.item.showInMyPublications = Show in My Publications
|
||||
pane.item.hideFromMyPublications = Hide from My Publications
|
||||
pane.item.changeType.title = Change Item Type
|
||||
pane.item.changeType.text = Are you sure you want to change the item type?\n\nThe following fields will be lost:
|
||||
pane.item.defaultFirstName = first
|
||||
|
@ -536,7 +543,7 @@ save.link = Saving Link…
|
|||
save.link.error = An error occurred while saving this link.
|
||||
save.error.cannotMakeChangesToCollection = You cannot make changes to the currently selected collection.
|
||||
save.error.cannotAddFilesToCollection = You cannot add files to the currently selected collection.
|
||||
save.error.cannotAddToMyPublications = You cannot save items directly to My Publications. To add items to My Publications, drag them from another library.
|
||||
save.error.cannotAddToMyPublications = You cannot save items directly to My Publications. To add items, drag them from elsewhere in your library.
|
||||
save.error.cannotAddToFeed = You cannot save items to feeds.
|
||||
|
||||
ingester.saveToZotero = Save to Zotero
|
||||
|
@ -1096,7 +1103,7 @@ styles.editor.output.singleCitation = Single Citation (with position "first")
|
|||
styles.preview.instructions = Select one or more items in Zotero and click the "Refresh" button to see how these items are rendered by the installed CSL citation styles.
|
||||
|
||||
publications.intro.text1 = My Publications allows you to create a list of your own work and share it on your profile page on %S. You can add notes about each item and even share PDFs or other files under a license you specify.
|
||||
publications.intro.text2 = To add items, drag them from another library. You’ll be able to choose whether to include attached notes and files.
|
||||
publications.intro.text2 = To add items, drag them from elsewhere in your library. You’ll be able to choose whether to include attached notes and files.
|
||||
publications.intro.text3 = <b>Only add work you yourself have created</b>, and only include files if you have the rights to distribute them publicly and wish to do so.
|
||||
publications.intro.authorship = I created this work.
|
||||
publications.intro.authorship.files = I created this work and have the rights to distribute included files.
|
||||
|
|
|
@ -421,8 +421,7 @@
|
|||
list-style-image: url('chrome://zotero/skin/arrow_refresh.png');
|
||||
}
|
||||
|
||||
.zotero-menuitem-delete-collection
|
||||
{
|
||||
.zotero-menuitem-delete-collection, .zotero-menuitem-remove-items {
|
||||
list-style-image: url('chrome://zotero/skin/toolbar-collection-delete.png');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- 92
|
||||
-- 93
|
||||
|
||||
-- Copyright (c) 2009 Center for History and New Media
|
||||
-- George Mason University, Fairfax, Virginia, USA
|
||||
|
@ -282,6 +282,10 @@ CREATE TABLE groupItems (
|
|||
FOREIGN KEY (lastModifiedByUserID) REFERENCES users(userID) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE publicationsItems (
|
||||
itemID INTEGER PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE fulltextItems (
|
||||
itemID INTEGER PRIMARY KEY,
|
||||
indexedPages INT,
|
||||
|
|
|
@ -608,6 +608,157 @@ describe("Zotero.CollectionTreeView", function() {
|
|||
assert.equal(treeRow.ref.id, item.id);
|
||||
});
|
||||
|
||||
describe("My Publications", function () {
|
||||
it("should add an item to My Publications", function* () {
|
||||
var item = yield createDataObject('item', false, { skipSelect: true });
|
||||
var libraryID = item.libraryID;
|
||||
|
||||
var stub = sinon.stub(zp, "showPublicationsWizard")
|
||||
.returns({
|
||||
includeNotes: false,
|
||||
includeFiles: false,
|
||||
keepRights: true
|
||||
});
|
||||
|
||||
// Add observer to wait for item modification
|
||||
var deferred = Zotero.Promise.defer();
|
||||
var observerID = Zotero.Notifier.registerObserver({
|
||||
notify: function (event, type, ids, extraData) {
|
||||
if (type == 'item' && event == 'modify' && ids[0] == item.id) {
|
||||
setTimeout(function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 'item', 'test');
|
||||
|
||||
yield drop('item', 'P' + libraryID, [item.id], deferred.promise);
|
||||
|
||||
Zotero.Notifier.unregisterObserver(observerID);
|
||||
stub.restore();
|
||||
|
||||
// Select publications and check for item
|
||||
yield cv.selectByID("P" + libraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var itemsView = win.ZoteroPane.itemsView
|
||||
assert.equal(itemsView.rowCount, 1);
|
||||
var treeRow = itemsView.getRow(0);
|
||||
assert.equal(treeRow.ref.id, item.id);
|
||||
});
|
||||
|
||||
it("should add an item with a file attachment to My Publications", function* () {
|
||||
var item = yield createDataObject('item', false, { skipSelect: true });
|
||||
var attachment = yield importFileAttachment('test.png', { parentItemID: item.id });
|
||||
var libraryID = item.libraryID;
|
||||
|
||||
var stub = sinon.stub(zp, "showPublicationsWizard")
|
||||
.returns({
|
||||
includeNotes: false,
|
||||
includeFiles: true,
|
||||
keepRights: true
|
||||
});
|
||||
|
||||
// Add observer to wait for modify
|
||||
var deferred = Zotero.Promise.defer();
|
||||
var observerID = Zotero.Notifier.registerObserver({
|
||||
notify: function (event, type, ids, extraData) {
|
||||
if (type == 'item' && event == 'modify' && ids[0] == item.id) {
|
||||
setTimeout(function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 'item', 'test');
|
||||
|
||||
yield drop('item', 'P' + libraryID, [item.id], deferred.promise);
|
||||
|
||||
Zotero.Notifier.unregisterObserver(observerID);
|
||||
stub.restore();
|
||||
|
||||
assert.isTrue(item.inPublications);
|
||||
// File attachment should be in My Publications
|
||||
assert.isTrue(attachment.inPublications);
|
||||
});
|
||||
|
||||
it("should add an item with a linked URL attachment to My Publications", function* () {
|
||||
var item = yield createDataObject('item', false, { skipSelect: true });
|
||||
var attachment = yield Zotero.Attachments.linkFromURL({
|
||||
parentItemID: item.id,
|
||||
title: 'Test',
|
||||
url: 'http://127.0.0.1/',
|
||||
contentType: 'text/html'
|
||||
});
|
||||
var libraryID = item.libraryID;
|
||||
|
||||
var stub = sinon.stub(zp, "showPublicationsWizard")
|
||||
.returns({
|
||||
includeNotes: false,
|
||||
includeFiles: false,
|
||||
keepRights: true
|
||||
});
|
||||
|
||||
// Add observer to wait for modify
|
||||
var deferred = Zotero.Promise.defer();
|
||||
var observerID = Zotero.Notifier.registerObserver({
|
||||
notify: function (event, type, ids, extraData) {
|
||||
if (type == 'item' && event == 'modify' && ids[0] == item.id) {
|
||||
setTimeout(function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 'item', 'test');
|
||||
|
||||
yield drop('item', 'P' + libraryID, [item.id], deferred.promise);
|
||||
|
||||
Zotero.Notifier.unregisterObserver(observerID);
|
||||
stub.restore();
|
||||
|
||||
assert.isTrue(item.inPublications);
|
||||
// Link attachment should be in My Publications
|
||||
assert.isTrue(attachment.inPublications);
|
||||
});
|
||||
|
||||
it("shouldn't add linked file attachment to My Publications", function* () {
|
||||
var item = yield createDataObject('item', false, { skipSelect: true });
|
||||
var attachment = yield Zotero.Attachments.linkFromFile({
|
||||
parentItemID: item.id,
|
||||
title: 'Test',
|
||||
file: OS.Path.join(getTestDataDirectory().path, 'test.png'),
|
||||
contentType: 'image/png'
|
||||
});
|
||||
var libraryID = item.libraryID;
|
||||
|
||||
var stub = sinon.stub(zp, "showPublicationsWizard")
|
||||
.returns({
|
||||
includeNotes: false,
|
||||
includeFiles: false,
|
||||
keepRights: true
|
||||
});
|
||||
|
||||
// Add observer to wait for modify
|
||||
var deferred = Zotero.Promise.defer();
|
||||
var observerID = Zotero.Notifier.registerObserver({
|
||||
notify: function (event, type, ids, extraData) {
|
||||
if (type == 'item' && event == 'modify' && ids[0] == item.id) {
|
||||
setTimeout(function () {
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 'item', 'test');
|
||||
|
||||
yield drop('item', 'P' + libraryID, [item.id], deferred.promise);
|
||||
|
||||
Zotero.Notifier.unregisterObserver(observerID);
|
||||
stub.restore();
|
||||
|
||||
assert.isTrue(item.inPublications);
|
||||
// Linked URL attachment shouldn't be in My Publications
|
||||
assert.isFalse(attachment.inPublications);
|
||||
});
|
||||
});
|
||||
|
||||
it("should copy an item with an attachment to a group", function* () {
|
||||
var group = yield createGroup();
|
||||
|
||||
|
|
|
@ -336,6 +336,36 @@ describe("Zotero.Item", function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe("#inPublications", function () {
|
||||
it("should add item to publications table", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
item.inPublications = true;
|
||||
yield item.saveTx();
|
||||
assert.ok(item.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
|
||||
1
|
||||
);
|
||||
})
|
||||
|
||||
it("should be set to false after save", function* () {
|
||||
var collection = yield createDataObject('collection');
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.inPublications = false;
|
||||
yield item.saveTx();
|
||||
|
||||
item.inPublications = false;
|
||||
yield item.saveTx();
|
||||
assert.isFalse(item.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
|
||||
0
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
describe("#parentID", function () {
|
||||
it("should create a child note", function* () {
|
||||
var item = new Zotero.Item('book');
|
||||
|
@ -1168,6 +1198,25 @@ describe("Zotero.Item", function () {
|
|||
assert.notProperty(json, "filename");
|
||||
assert.notProperty(json, "path");
|
||||
});
|
||||
|
||||
it("should include inPublications=true for items in My Publications", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.inPublications = true;
|
||||
var json = item.toJSON();
|
||||
assert.propertyVal(json, "inPublications", true);
|
||||
});
|
||||
|
||||
it("shouldn't include inPublications for items not in My Publications in patch mode", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
var json = item.toJSON();
|
||||
assert.notProperty(json, "inPublications");
|
||||
});
|
||||
|
||||
it("should include inPublications=false for items not in My Publications in full mode", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
var json = item.toJSON({ mode: 'full' });
|
||||
assert.property(json, "inPublications", false);
|
||||
});
|
||||
})
|
||||
|
||||
describe("'full' mode", function () {
|
||||
|
|
|
@ -529,8 +529,85 @@ describe("Zotero.ItemTreeView", function() {
|
|||
});
|
||||
assert.isFalse(zp.itemsView.getRowIndexByID(item.id));
|
||||
});
|
||||
|
||||
describe("My Publications", function () {
|
||||
before(function* () {
|
||||
var libraryID = Zotero.Libraries.userLibraryID;
|
||||
|
||||
var s = new Zotero.Search;
|
||||
s.libraryID = libraryID;
|
||||
s.addCondition('publications', 'true');
|
||||
var ids = yield s.search();
|
||||
|
||||
yield Zotero.Items.erase(ids);
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + libraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
|
||||
// Make sure we're showing the intro text
|
||||
var deck = win.document.getElementById('zotero-items-pane-content');
|
||||
assert.equal(deck.selectedIndex, 1);
|
||||
});
|
||||
|
||||
it("should replace My Publications intro text with items list on item add", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + item.libraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var iv = zp.itemsView;
|
||||
|
||||
item.inPublications = true;
|
||||
yield item.saveTx();
|
||||
|
||||
var deck = win.document.getElementById('zotero-items-pane-content');
|
||||
assert.equal(deck.selectedIndex, 0);
|
||||
|
||||
assert.isNumber(iv.getRowIndexByID(item.id));
|
||||
});
|
||||
|
||||
it("should add new item to My Publications items list", function* () {
|
||||
var item1 = createUnsavedDataObject('item');
|
||||
item1.inPublications = true;
|
||||
yield item1.saveTx();
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + item1.libraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var iv = zp.itemsView;
|
||||
|
||||
var deck = win.document.getElementById('zotero-items-pane-content');
|
||||
assert.equal(deck.selectedIndex, 0);
|
||||
|
||||
var item2 = createUnsavedDataObject('item');
|
||||
item2.inPublications = true;
|
||||
yield item2.saveTx();
|
||||
|
||||
assert.isNumber(iv.getRowIndexByID(item2.id));
|
||||
});
|
||||
|
||||
it("should add modified item to My Publications items list", function* () {
|
||||
var item1 = createUnsavedDataObject('item');
|
||||
item1.inPublications = true;
|
||||
yield item1.saveTx();
|
||||
var item2 = yield createDataObject('item');
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + item1.libraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var iv = zp.itemsView;
|
||||
|
||||
var deck = win.document.getElementById('zotero-items-pane-content');
|
||||
assert.equal(deck.selectedIndex, 0);
|
||||
|
||||
assert.isFalse(iv.getRowIndexByID(item2.id));
|
||||
|
||||
item2.inPublications = true;
|
||||
yield item2.saveTx();
|
||||
|
||||
assert.isNumber(iv.getRowIndexByID(item2.id));
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
describe("#drop()", function () {
|
||||
var httpd;
|
||||
var port = 16213;
|
||||
|
|
|
@ -15,6 +15,144 @@ describe("Zotero.Items", function () {
|
|||
})
|
||||
|
||||
|
||||
describe("#addToPublications", function () {
|
||||
it("should add an item to My Publications", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
yield Zotero.Items.addToPublications([item]);
|
||||
assert.isTrue(item.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
describe("#license", function () {
|
||||
it("should set a license if specified", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.setField('rights', 'Test');
|
||||
yield item.saveTx();
|
||||
yield Zotero.Items.addToPublications(
|
||||
[item],
|
||||
{
|
||||
license: 'reserved',
|
||||
licenseName: 'All Rights Reserved',
|
||||
keepRights: false
|
||||
}
|
||||
);
|
||||
assert.equal(item.getField('rights'), 'All Rights Reserved');
|
||||
});
|
||||
|
||||
it("should keep existing Rights field if .keepRights is true", function* () {
|
||||
var item1 = createUnsavedDataObject('item');
|
||||
item1.setField('rights', 'Test');
|
||||
yield item1.saveTx();
|
||||
var item2 = yield createDataObject('item');
|
||||
yield Zotero.Items.addToPublications(
|
||||
[item1, item2],
|
||||
{
|
||||
license: 'reserved',
|
||||
licenseName: 'All Rights Reserved',
|
||||
keepRights: true
|
||||
}
|
||||
);
|
||||
assert.equal(item1.getField('rights'), 'Test');
|
||||
assert.equal(item2.getField('rights'), 'All Rights Reserved');
|
||||
});
|
||||
|
||||
it("shouldn't set a license if not specified", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.setField('rights', 'Test');
|
||||
yield item.saveTx();
|
||||
yield Zotero.Items.addToPublications([item]);
|
||||
assert.equal(item.getField('rights'), 'Test');
|
||||
});
|
||||
});
|
||||
|
||||
it("should add child notes if .childNotes is true", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
|
||||
var attachment = yield Zotero.Attachments.linkFromURL({
|
||||
url: "http://example.com",
|
||||
parentItemID: item.id,
|
||||
title: "Example"
|
||||
});
|
||||
|
||||
yield Zotero.Items.addToPublications([item], { childNotes: true });
|
||||
assert.isTrue(note.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", note.id)),
|
||||
1
|
||||
);
|
||||
assert.isFalse(attachment.inPublications);
|
||||
});
|
||||
|
||||
it("should add child link attachments if .childLinks is true", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
var attachment1 = yield Zotero.Attachments.linkFromURL({
|
||||
url: "http://example.com",
|
||||
parentItemID: item.id,
|
||||
title: "Example"
|
||||
});
|
||||
var attachment2 = yield importFileAttachment('test.png', { parentItemID: item.id });
|
||||
var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
|
||||
|
||||
yield Zotero.Items.addToPublications([item], { childLinks: true });
|
||||
assert.isTrue(attachment1.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", attachment1.id)),
|
||||
1
|
||||
);
|
||||
assert.isFalse(attachment2.inPublications);
|
||||
assert.isFalse(note.inPublications);
|
||||
});
|
||||
|
||||
it("should add child file attachments if .childFileAttachments is true", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
var attachment1 = yield importFileAttachment('test.png', { parentItemID: item.id });
|
||||
var attachment2 = yield Zotero.Attachments.linkFromURL({
|
||||
url: "http://example.com",
|
||||
parentItemID: item.id,
|
||||
title: "Example"
|
||||
});
|
||||
var note = yield createDataObject('item', { itemType: 'note', parentID: item.id });
|
||||
|
||||
yield Zotero.Items.addToPublications([item], { childFileAttachments: true });
|
||||
assert.isTrue(attachment1.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", attachment1.id)),
|
||||
1
|
||||
);
|
||||
assert.isFalse(attachment2.inPublications);
|
||||
assert.isFalse(note.inPublications);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("#removeFromPublications", function () {
|
||||
it("should remove an item from My Publications", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
item.inPublications = true;
|
||||
yield item.saveTx();
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
|
||||
1
|
||||
);
|
||||
yield Zotero.Items.removeFromPublications([item]);
|
||||
assert.isFalse(item.inPublications);
|
||||
assert.equal(
|
||||
(yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT COUNT(*) FROM publicationsItems WHERE itemID=?", item.id)),
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("#merge()", function () {
|
||||
it("should merge two items", function* () {
|
||||
var item1 = yield createDataObject('item');
|
||||
|
|
|
@ -1406,6 +1406,43 @@ describe("Zotero.Sync.Data.Local", function() {
|
|||
]
|
||||
);
|
||||
});
|
||||
|
||||
it("should automatically apply inPublications setting from remote", function () {
|
||||
var cacheJSON = {
|
||||
key: "AAAAAAAA",
|
||||
version: 1234,
|
||||
title: "Title 1",
|
||||
dateModified: "2017-04-02 12:34:56"
|
||||
};
|
||||
var json1 = {
|
||||
key: "AAAAAAAA",
|
||||
version: 1234,
|
||||
title: "Title 1",
|
||||
dateModified: "2017-04-02 12:34:56"
|
||||
};
|
||||
var json2 = {
|
||||
key: "AAAAAAAA",
|
||||
version: 1235,
|
||||
title: "Title 1",
|
||||
inPublications: true,
|
||||
dateModified: "2017-04-03 12:34:56"
|
||||
};
|
||||
var ignoreFields = ['dateAdded', 'dateModified'];
|
||||
var result = Zotero.Sync.Data.Local._reconcileChanges(
|
||||
'item', cacheJSON, json1, json2, ignoreFields
|
||||
);
|
||||
assert.lengthOf(result.changes, 1);
|
||||
assert.sameDeepMembers(
|
||||
result.changes,
|
||||
[
|
||||
{
|
||||
field: "inPublications",
|
||||
op: "add",
|
||||
value: true
|
||||
}
|
||||
]
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -230,6 +230,80 @@ describe("ZoteroPane", function() {
|
|||
})
|
||||
})
|
||||
|
||||
|
||||
describe("#deleteSelectedItems()", function () {
|
||||
it("should remove an item from My Publications", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.inPublications = true;
|
||||
yield item.saveTx();
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + userLibraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var iv = zp.itemsView;
|
||||
|
||||
var selected = iv.selectItem(item.id);
|
||||
assert.ok(selected);
|
||||
|
||||
var tree = doc.getElementById('zotero-items-tree');
|
||||
tree.focus();
|
||||
|
||||
yield Zotero.Promise.delay(1);
|
||||
|
||||
var promise = waitForDialog();
|
||||
var modifyPromise = waitForItemEvent('modify');
|
||||
|
||||
var event = doc.createEvent("KeyboardEvent");
|
||||
event.initKeyEvent("keypress", true, true, window, false, false, false, false, 46, 0);
|
||||
tree.dispatchEvent(event);
|
||||
yield promise;
|
||||
yield modifyPromise;
|
||||
|
||||
assert.isFalse(item.inPublications);
|
||||
assert.isFalse(item.deleted);
|
||||
});
|
||||
|
||||
it("should move an item to trash from My Publications", function* () {
|
||||
var item = createUnsavedDataObject('item');
|
||||
item.inPublications = true;
|
||||
yield item.saveTx();
|
||||
|
||||
yield zp.collectionsView.selectByID("P" + userLibraryID);
|
||||
yield waitForItemsLoad(win);
|
||||
var iv = zp.itemsView;
|
||||
|
||||
var selected = iv.selectItem(item.id);
|
||||
assert.ok(selected);
|
||||
|
||||
var tree = doc.getElementById('zotero-items-tree');
|
||||
tree.focus();
|
||||
|
||||
yield Zotero.Promise.delay(1);
|
||||
|
||||
var promise = waitForDialog();
|
||||
var modifyPromise = waitForItemEvent('modify');
|
||||
|
||||
var event = doc.createEvent("KeyboardEvent");
|
||||
event.initKeyEvent(
|
||||
"keypress",
|
||||
true,
|
||||
true,
|
||||
window,
|
||||
false,
|
||||
false,
|
||||
!Zotero.isMac, // shift
|
||||
Zotero.isMac, // meta
|
||||
46,
|
||||
0
|
||||
);
|
||||
tree.dispatchEvent(event);
|
||||
yield promise;
|
||||
yield modifyPromise;
|
||||
|
||||
assert.isTrue(item.inPublications);
|
||||
assert.isTrue(item.deleted);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#deleteSelectedCollection()", function () {
|
||||
it("should delete collection but not descendant items by default", function* () {
|
||||
var collection = yield createDataObject('collection');
|
||||
|
|
Loading…
Reference in a new issue