Don't accept keyboard input before new-collection prompt appears
Fixes #1613
This commit is contained in:
parent
4bc8fab4f5
commit
7575cd8b29
5 changed files with 92 additions and 44 deletions
|
@ -107,14 +107,16 @@ var ZoteroAdvancedSearch = new function() {
|
|||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
|
||||
var untitled = yield Zotero.DB.getNextName(
|
||||
_searchBox.search.libraryID,
|
||||
'savedSearches',
|
||||
'savedSearchName',
|
||||
Zotero.getString('pane.collections.untitled')
|
||||
var libraryID = _searchBox.search.libraryID;
|
||||
|
||||
var searches = yield Zotero.Searches.getAll(libraryID)
|
||||
var prefix = Zotero.getString('pane.collections.untitled');
|
||||
var name = Zotero.Utilities.Internal.getNextName(
|
||||
prefix,
|
||||
searches.map(s => s.name).filter(n => n.startsWith(prefix))
|
||||
);
|
||||
|
||||
var name = { value: untitled };
|
||||
var name = { value: name };
|
||||
var result = promptService.prompt(window,
|
||||
Zotero.getString('pane.collections.newSavedSeach'),
|
||||
Zotero.getString('pane.collections.savedSearchName'), name, "", {});
|
||||
|
|
|
@ -104,8 +104,8 @@ Zotero.Searches = function() {
|
|||
|
||||
|
||||
this.getNextName = async function (libraryID, name) {
|
||||
// Trim '(1)', etc.
|
||||
var matches = name.match(/^(.+) \(\d+\)$/);
|
||||
// Trim '1', etc.
|
||||
var matches = name.match(/^(.+) \d+$/);
|
||||
if (matches) {
|
||||
name = matches[1].trim();
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ Zotero.Searches = function() {
|
|||
sql,
|
||||
[libraryID, Zotero.DB.escapeSQLExpression(name) + '%']
|
||||
);
|
||||
return Zotero.Utilities.Internal.getNextName(name, names);
|
||||
return Zotero.Utilities.Internal.getNextName(name, names, true);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1194,23 +1194,51 @@ Zotero.Utilities.Internal = {
|
|||
/**
|
||||
* Get the next available numbered name that matches a base name, for use when duplicating
|
||||
*
|
||||
* - Given 'Foo' and ['Foo'], returns 'Foo (1)'.
|
||||
* - Given 'Foo (1)' and ['Foo', 'Foo (1)'], returns 'Foo (2)'
|
||||
* - Given 'Foo' and ['Foo'], returns 'Foo 1'.
|
||||
* - Given 'Foo' and ['Foo', 'Foo 1'], returns 'Foo 2'.
|
||||
* - Given 'Foo' and ['Foo', 'Foo 1'], returns 'Foo 2'.
|
||||
* - Given 'Foo 1', ['Foo', 'Foo 1'], and trim=true, returns 'Foo 2'
|
||||
* - Given 'Foo' and ['Foo', 'Foo 2'], returns 'Foo 1'
|
||||
*/
|
||||
getNextName: function (name, existingNames) {
|
||||
// Trim '(1)', etc.
|
||||
var matches = name.match(/^(.+) \(\d+\)$/);
|
||||
if (matches) {
|
||||
name = matches[1].trim();
|
||||
}
|
||||
var highest = 0;
|
||||
for (let existingName of existingNames) {
|
||||
let matches = existingName.match(/ \((\d+)\)$/);
|
||||
if (matches && matches[1] > highest) {
|
||||
highest = matches[1];
|
||||
getNextName: function (name, existingNames, trim = false) {
|
||||
// Trim numbers at end of given name
|
||||
if (trim) {
|
||||
let matches = name.match(/^(.+) \d+$/);
|
||||
if (matches) {
|
||||
name = matches[1].trim();
|
||||
}
|
||||
}
|
||||
return name + ' (' + ++highest + ')';
|
||||
|
||||
if (!existingNames.includes(name)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
var suffixes = existingNames
|
||||
// Get suffix
|
||||
.map(x => x.substr(name.length))
|
||||
// Get "2", "5", etc.
|
||||
.filter(x => x.match(/^ (\d+)$/));
|
||||
|
||||
suffixes.sort(function (a, b) {
|
||||
return parseInt(a) - parseInt(b);
|
||||
});
|
||||
|
||||
// If no existing numbered names found, use 1
|
||||
if (!suffixes.length) {
|
||||
return name + ' ' + 1;
|
||||
}
|
||||
|
||||
// Find first available number
|
||||
var i = 0;
|
||||
var num = 1;
|
||||
while (suffixes[i] == num) {
|
||||
while (suffixes[i + 1] && suffixes[i] == suffixes[i + 1]) {
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
num++;
|
||||
}
|
||||
return name + ' ' + num;
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -912,17 +912,23 @@ var ZoteroPane = new function()
|
|||
|
||||
var libraryID = this.getSelectedLibraryID();
|
||||
|
||||
var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPromptService);
|
||||
var untitled = yield Zotero.DB.getNextName(
|
||||
libraryID,
|
||||
'collections',
|
||||
'collectionName',
|
||||
Zotero.getString('pane.collections.untitled')
|
||||
// Get a unique "Untitled" name for this level in the collection hierarchy
|
||||
var collections;
|
||||
if (parentKey) {
|
||||
let parent = Zotero.Collections.getIDFromLibraryAndKey(libraryID, parentKey);
|
||||
collections = Zotero.Collections.getByParent(parent);
|
||||
}
|
||||
else {
|
||||
collections = Zotero.Collections.getByLibrary(libraryID);
|
||||
}
|
||||
var prefix = Zotero.getString('pane.collections.untitled');
|
||||
var name = Zotero.Utilities.Internal.getNextName(
|
||||
prefix,
|
||||
collections.map(c => c.name).filter(n => n.startsWith(prefix))
|
||||
);
|
||||
|
||||
var newName = { value: untitled };
|
||||
var result = promptService.prompt(window,
|
||||
var newName = { value: name };
|
||||
var result = Services.prompt.prompt(window,
|
||||
Zotero.getString('pane.collections.newCollection'),
|
||||
Zotero.getString('pane.collections.name'), newName, "", {});
|
||||
|
||||
|
@ -991,18 +997,20 @@ var ZoteroPane = new function()
|
|||
yield Zotero.DB.waitForTransaction();
|
||||
}
|
||||
|
||||
var libraryID = this.getSelectedLibraryID();
|
||||
|
||||
var s = new Zotero.Search();
|
||||
s.libraryID = this.getSelectedLibraryID();
|
||||
s.libraryID = libraryID;
|
||||
s.addCondition('title', 'contains', '');
|
||||
|
||||
var untitled = Zotero.getString('pane.collections.untitled');
|
||||
untitled = yield Zotero.DB.getNextName(
|
||||
s.libraryID,
|
||||
'savedSearches',
|
||||
'savedSearchName',
|
||||
Zotero.getString('pane.collections.untitled')
|
||||
var searches = yield Zotero.Searches.getAll(libraryID)
|
||||
var prefix = Zotero.getString('pane.collections.untitled');
|
||||
var name = Zotero.Utilities.Internal.getNextName(
|
||||
prefix,
|
||||
searches.map(s => s.name).filter(n => n.startsWith(prefix))
|
||||
);
|
||||
var io = {dataIn: {search: s, name: untitled}, dataOut: null};
|
||||
|
||||
var io = { dataIn: { search: s, name }, dataOut: null };
|
||||
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
||||
if (!io.dataOut) {
|
||||
return false;
|
||||
|
|
|
@ -203,13 +203,23 @@ describe("Zotero.Utilities.Internal", function () {
|
|||
|
||||
describe("#getNextName()", function () {
|
||||
it("should get the next available numbered name", function () {
|
||||
var existing = ['Name (1)', 'Name (3)'];
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name', existing), 'Name (4)');
|
||||
var existing = ['Name', 'Name 1', 'Name 3'];
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name', existing), 'Name 2');
|
||||
});
|
||||
|
||||
it("should return 'Name (1)' if no numbered names", function () {
|
||||
it("should return 'Name 1' if no numbered names", function () {
|
||||
var existing = ['Name'];
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name', existing), 'Name (1)');
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name', existing), 'Name 1');
|
||||
});
|
||||
|
||||
it("should return 'Name' if only numbered names", function () {
|
||||
var existing = ['Name 1', 'Name 3'];
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name', existing), 'Name');
|
||||
});
|
||||
|
||||
it("should trim given name if trim=true", function () {
|
||||
var existing = ['Name', 'Name 1', 'Name 2', 'Name 3'];
|
||||
assert.equal(Zotero.Utilities.Internal.getNextName('Name 2', existing, true), 'Name 4');
|
||||
});
|
||||
});
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue