diff --git a/chrome/content/zotero/xpcom/data/searches.js b/chrome/content/zotero/xpcom/data/searches.js
index 7198cf98d3..e402e7d987 100644
--- a/chrome/content/zotero/xpcom/data/searches.js
+++ b/chrome/content/zotero/xpcom/data/searches.js
@@ -103,6 +103,22 @@ Zotero.Searches = function() {
},
+ this.getNextName = async function (libraryID, name) {
+ // Trim '(1)', etc.
+ var matches = name.match(/^(.+) \(\d+\)$/);
+ if (matches) {
+ name = matches[1].trim();
+ }
+ var sql = "SELECT savedSearchName FROM savedSearches "
+ + "WHERE libraryID=? AND savedSearchName LIKE ? ESCAPE '\\'";
+ var names = await Zotero.DB.columnQueryAsync(
+ sql,
+ [libraryID, Zotero.DB.escapeSQLExpression(name) + '%']
+ );
+ return Zotero.Utilities.Internal.getNextName(name, names);
+ };
+
+
this._loadConditions = Zotero.Promise.coroutine(function* (libraryID, ids, idSQL) {
var sql = "SELECT savedSearchID, searchConditionID, condition, operator, value, required "
+ "FROM savedSearches LEFT JOIN savedSearchConditions USING (savedSearchID) "
diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js
index 7e2cb2472b..540e8eece3 100644
--- a/chrome/content/zotero/zoteroPane.js
+++ b/chrome/content/zotero/zoteroPane.js
@@ -2056,6 +2056,24 @@ var ZoteroPane = new function()
});
+ // Currently only works on searches
+ this.duplicateSelectedCollection = async function () {
+ if (!this.canEdit()) {
+ this.displayCannotEditLibraryMessage();
+ return;
+ }
+
+ if (this.collectionsView.selection.count == 0) {
+ return;
+ }
+
+ var row = this.collectionsView.selectedTreeRow;
+ let o = row.ref.clone();
+ o.name = await row.ref.ObjectsClass.getNextName(row.ref.libraryID, o.name);
+ await o.saveTx();
+ };
+
+
this.editSelectedCollection = Zotero.Promise.coroutine(function* () {
if (!this.canEdit()) {
this.displayCannotEditLibraryMessage();
@@ -2453,6 +2471,10 @@ var ZoteroPane = new function()
id: "editSelectedCollection",
oncommand: () => this.editSelectedCollection()
},
+ {
+ id: "duplicate",
+ oncommand: () => this.duplicateSelectedCollection()
+ },
{
id: "markReadFeed",
oncommand: () => this.markFeedRead()
@@ -2611,6 +2633,7 @@ var ZoteroPane = new function()
else if (collectionTreeRow.isSearch()) {
show = [
'editSelectedCollection',
+ 'duplicate',
'deleteCollection',
'sep3',
'exportCollection',
@@ -2618,7 +2641,6 @@ var ZoteroPane = new function()
'loadReport'
];
- m.deleteCollection.setAttribute('label', Zotero.getString('pane.collections.menu.delete.savedSearch'));
if (!this.itemsView.rowCount) {
disable.push('exportCollection', 'createBibCollection', 'loadReport');
@@ -2626,6 +2648,8 @@ var ZoteroPane = new function()
// Adjust labels
m.editSelectedCollection.setAttribute('label', Zotero.getString('pane.collections.menu.edit.savedSearch'));
+ m.duplicate.setAttribute('label', Zotero.getString('pane.collections.menu.duplicate.savedSearch'));
+ m.deleteCollection.setAttribute('label', Zotero.getString('pane.collections.menu.delete.savedSearch'));
m.exportCollection.setAttribute('label', Zotero.getString('pane.collections.menu.export.savedSearch'));
m.createBibCollection.setAttribute('label', Zotero.getString('pane.collections.menu.createBib.savedSearch'));
m.loadReport.setAttribute('label', Zotero.getString('pane.collections.menu.generateReport.savedSearch'));
@@ -2693,6 +2717,7 @@ var ZoteroPane = new function()
disable.push(
'newSubcollection',
'editSelectedCollection',
+ 'duplicate',
'deleteCollection',
'deleteCollectionAndItems'
);
diff --git a/chrome/content/zotero/zoteroPane.xul b/chrome/content/zotero/zoteroPane.xul
index 797a3e7a82..adff5bfeae 100644
--- a/chrome/content/zotero/zoteroPane.xul
+++ b/chrome/content/zotero/zoteroPane.xul
@@ -227,6 +227,7 @@
+
diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties
index 619196895e..e26ed591bb 100644
--- a/chrome/locale/en-US/zotero/zotero.properties
+++ b/chrome/locale/en-US/zotero/zotero.properties
@@ -237,6 +237,7 @@ pane.collections.removeLibrary = Remove Library
pane.collections.removeLibrary.text = Are you sure you want to permanently remove “%S” from this computer?
pane.collections.menu.rename.collection = Rename Collection…
+pane.collections.menu.duplicate.savedSearch = Duplicate Saved Search
pane.collections.menu.edit.savedSearch = Edit Saved Search…
pane.collections.menu.edit.feed = Edit Feed…
pane.collections.menu.remove.library = Remove Library…