Sort descendant collections alphabetically in advanced search window
https://forums.zotero.org/discussion/50679/
This commit is contained in:
parent
984789d304
commit
a452af6c3a
3 changed files with 149 additions and 129 deletions
|
@ -405,130 +405,130 @@
|
||||||
]]>
|
]]>
|
||||||
</constructor>
|
</constructor>
|
||||||
<method name="onConditionSelected">
|
<method name="onConditionSelected">
|
||||||
<body>
|
<body><![CDATA[
|
||||||
<![CDATA[
|
return Zotero.spawn(function* () {
|
||||||
// Skip if correct condition already selected
|
// Skip if correct condition already selected
|
||||||
if (this.id('conditionsmenu').value==this.selectedCondition){
|
if (this.id('conditionsmenu').value==this.selectedCondition){
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
var conditionsMenu = this.id('conditionsmenu');
|
|
||||||
var operatorsList = this.id('operatorsmenu');
|
|
||||||
|
|
||||||
this.selectedCondition = conditionsMenu.value;
|
|
||||||
this.selectedOperator = operatorsList.value;
|
|
||||||
|
|
||||||
var condition = Zotero.SearchConditions.get(conditionsMenu.value);
|
|
||||||
var operators = condition['operators'];
|
|
||||||
|
|
||||||
// Display appropriate operators for condition
|
|
||||||
var selectThis;
|
|
||||||
for(var i = 0, len = operatorsList.firstChild.childNodes.length; i < len; i++)
|
|
||||||
{
|
|
||||||
var val = operatorsList.firstChild.childNodes[i].getAttribute('value');
|
|
||||||
var hidden = !operators[val];
|
|
||||||
operatorsList.firstChild.childNodes[i].setAttribute('hidden', hidden);
|
|
||||||
if (!hidden && (selectThis == null || this.selectedOperator == val))
|
|
||||||
{
|
|
||||||
selectThis = i;
|
|
||||||
}
|
}
|
||||||
}
|
var conditionsMenu = this.id('conditionsmenu');
|
||||||
operatorsList.selectedIndex = selectThis;
|
var operatorsList = this.id('operatorsmenu');
|
||||||
|
|
||||||
// Generate drop-down menu instead of textbox for certain conditions
|
|
||||||
switch (conditionsMenu.value){
|
|
||||||
case 'collection':
|
|
||||||
var rows = [];
|
|
||||||
|
|
||||||
var libraryID = this.parent.search.libraryID;
|
|
||||||
var cols = Zotero.getCollections(false, true, libraryID); // TODO: Replace with Zotero.Collections.getByLibrary()
|
|
||||||
for (var i in cols) {
|
|
||||||
// Indent subcollections
|
|
||||||
var indent = '';
|
|
||||||
if (cols[i].level) {
|
|
||||||
for (var j=1; j<cols[i].level; j++) {
|
|
||||||
indent += ' ';
|
|
||||||
}
|
|
||||||
indent += '- ';
|
|
||||||
}
|
|
||||||
rows.push([indent + cols[i].name, 'C' + cols[i].key]);
|
|
||||||
}
|
|
||||||
this.createValueMenu(rows);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'savedSearch':
|
this.selectedCondition = conditionsMenu.value;
|
||||||
var rows = [];
|
this.selectedOperator = operatorsList.value;
|
||||||
var libraryID = this.parent.search.libraryID;
|
|
||||||
var searches = Zotero.Searches.getAll(libraryID);
|
|
||||||
for (var i in searches) {
|
|
||||||
if (searches[i].id != this.parent.search.id) {
|
|
||||||
rows.push([searches[i].name, 'S' + searches[i].key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.createValueMenu(rows);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'itemType':
|
var condition = Zotero.SearchConditions.get(conditionsMenu.value);
|
||||||
var t = Zotero.ItemTypes.getTypes();
|
var operators = condition['operators'];
|
||||||
|
|
||||||
// Sort by localized name
|
|
||||||
var types = [];
|
|
||||||
for (var i=0; i<t.length; i++) {
|
|
||||||
types.push({
|
|
||||||
id: t[i].id,
|
|
||||||
name: t[i].name,
|
|
||||||
localized: Zotero.ItemTypes.getLocalizedString(t[i].id)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var collation = Zotero.getLocaleCollation();
|
|
||||||
types.sort(function(a, b) {
|
|
||||||
return collation.compareString(1, a.localized, b.localized);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (var i in types) {
|
|
||||||
types[i][0] = types[i].localized;
|
|
||||||
types[i][1] = types[i].name;
|
|
||||||
delete types[i]['name'];
|
|
||||||
delete types[i]['id'];
|
|
||||||
}
|
|
||||||
this.createValueMenu(types);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'fileTypeID':
|
// Display appropriate operators for condition
|
||||||
var types = Zotero.FileTypes.getTypes();
|
var selectThis;
|
||||||
for (var i in types) {
|
for(var i = 0, len = operatorsList.firstChild.childNodes.length; i < len; i++)
|
||||||
types[i][0] = Zotero.getString('fileTypes.' + types[i]['name']);
|
{
|
||||||
types[i][1] = types[i]['id'];
|
var val = operatorsList.firstChild.childNodes[i].getAttribute('value');
|
||||||
delete types[i]['name'];
|
var hidden = !operators[val];
|
||||||
delete types[i]['id'];
|
operatorsList.firstChild.childNodes[i].setAttribute('hidden', hidden);
|
||||||
}
|
if (!hidden && (selectThis == null || this.selectedOperator == val))
|
||||||
this.createValueMenu(types);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (operatorsList.value=='isInTheLast')
|
|
||||||
{
|
{
|
||||||
this.id('value-date-age').value = this.value;
|
selectThis = i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Textbox
|
operatorsList.selectedIndex = selectThis;
|
||||||
else {
|
|
||||||
// If switching from menu to textbox, clear value
|
// Generate drop-down menu instead of textbox for certain conditions
|
||||||
if (this.id('valuefield').hidden){
|
switch (conditionsMenu.value){
|
||||||
this.id('valuefield').value = '';
|
case 'collection':
|
||||||
|
var rows = [];
|
||||||
|
|
||||||
|
var libraryID = this.parent.search.libraryID;
|
||||||
|
var cols = yield Zotero.Collections.getByLibrary(libraryID, true);
|
||||||
|
for (var i in cols) {
|
||||||
|
// Indent subcollections
|
||||||
|
var indent = '';
|
||||||
|
if (cols[i].level) {
|
||||||
|
for (var j=1; j<cols[i].level; j++) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
indent += '- ';
|
||||||
|
}
|
||||||
|
rows.push([indent + cols[i].name, 'C' + cols[i].key]);
|
||||||
}
|
}
|
||||||
// If switching between textbox conditions, get loaded value for new one
|
this.createValueMenu(rows);
|
||||||
else {
|
break;
|
||||||
this.id('valuefield').value = this.value;
|
|
||||||
|
case 'savedSearch':
|
||||||
|
var rows = [];
|
||||||
|
var libraryID = this.parent.search.libraryID;
|
||||||
|
var searches = Zotero.Searches.getAll(libraryID);
|
||||||
|
for (var i in searches) {
|
||||||
|
if (searches[i].id != this.parent.search.id) {
|
||||||
|
rows.push([searches[i].name, 'S' + searches[i].key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.createValueMenu(rows);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'itemType':
|
||||||
|
var t = Zotero.ItemTypes.getTypes();
|
||||||
|
|
||||||
|
// Sort by localized name
|
||||||
|
var types = [];
|
||||||
|
for (var i=0; i<t.length; i++) {
|
||||||
|
types.push({
|
||||||
|
id: t[i].id,
|
||||||
|
name: t[i].name,
|
||||||
|
localized: Zotero.ItemTypes.getLocalizedString(t[i].id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var collation = Zotero.getLocaleCollation();
|
||||||
|
types.sort(function(a, b) {
|
||||||
|
return collation.compareString(1, a.localized, b.localized);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i in types) {
|
||||||
|
types[i][0] = types[i].localized;
|
||||||
|
types[i][1] = types[i].name;
|
||||||
|
delete types[i]['name'];
|
||||||
|
delete types[i]['id'];
|
||||||
|
}
|
||||||
|
this.createValueMenu(types);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'fileTypeID':
|
||||||
|
var types = Zotero.FileTypes.getTypes();
|
||||||
|
for (var i in types) {
|
||||||
|
types[i][0] = Zotero.getString('fileTypes.' + types[i]['name']);
|
||||||
|
types[i][1] = types[i]['id'];
|
||||||
|
delete types[i]['name'];
|
||||||
|
delete types[i]['id'];
|
||||||
|
}
|
||||||
|
this.createValueMenu(types);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (operatorsList.value=='isInTheLast')
|
||||||
|
{
|
||||||
|
this.id('value-date-age').value = this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update field drop-down if applicable
|
// Textbox
|
||||||
this.id('valuefield').update(conditionsMenu.value, this.mode);
|
else {
|
||||||
}
|
// If switching from menu to textbox, clear value
|
||||||
}
|
if (this.id('valuefield').hidden){
|
||||||
|
this.id('valuefield').value = '';
|
||||||
this.onOperatorSelected();
|
}
|
||||||
]]>
|
// If switching between textbox conditions, get loaded value for new one
|
||||||
</body>
|
else {
|
||||||
|
this.id('valuefield').value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update field drop-down if applicable
|
||||||
|
this.id('valuefield').update(conditionsMenu.value, this.mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onOperatorSelected();
|
||||||
|
}.bind(this));
|
||||||
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
<method name="onOperatorSelected">
|
<method name="onOperatorSelected">
|
||||||
<body>
|
<body>
|
||||||
|
@ -597,8 +597,8 @@
|
||||||
<method name="initWithParentAndCondition">
|
<method name="initWithParentAndCondition">
|
||||||
<parameter name="parent"/>
|
<parameter name="parent"/>
|
||||||
<parameter name="condition"/>
|
<parameter name="condition"/>
|
||||||
<body>
|
<body><![CDATA[
|
||||||
<![CDATA[
|
return Zotero.spawn(function* () {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.conditionID = condition['id'];
|
this.conditionID = condition['id'];
|
||||||
|
|
||||||
|
@ -638,11 +638,11 @@
|
||||||
this.dontupdate = false;
|
this.dontupdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onConditionSelected();
|
yield this.onConditionSelected();
|
||||||
|
|
||||||
this.id('conditionsmenu').focus();
|
this.id('conditionsmenu').focus();
|
||||||
]]>
|
}.bind(this));
|
||||||
</body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
<!-- Gets the value from the field and updates the associated search condition -->
|
<!-- Gets the value from the field and updates the associated search condition -->
|
||||||
<method name="updateSearch">
|
<method name="updateSearch">
|
||||||
|
|
|
@ -690,17 +690,21 @@ Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (re
|
||||||
|
|
||||||
// 0 == collection
|
// 0 == collection
|
||||||
// 1 == item
|
// 1 == item
|
||||||
var sql = 'SELECT collectionID AS id, '
|
var sql = 'SELECT collectionID AS id, collectionName AS name, '
|
||||||
+ "0 AS type, collectionName AS collectionName, key "
|
+ "0 AS type, collectionName AS collectionName, key "
|
||||||
+ 'FROM collections WHERE parentCollectionID=?1';
|
+ 'FROM collections WHERE parentCollectionID=?1';
|
||||||
if (!type || type == 'item') {
|
if (!type || type == 'item') {
|
||||||
sql += ' UNION SELECT itemID AS id, 1 AS type, NULL AS collectionName, key '
|
sql += ' UNION SELECT itemID AS id, NULL AS name, 1 AS type, NULL AS collectionName, key '
|
||||||
+ 'FROM collectionItems JOIN items USING (itemID) WHERE collectionID=?1';
|
+ 'FROM collectionItems JOIN items USING (itemID) WHERE collectionID=?1';
|
||||||
if (!includeDeletedItems) {
|
if (!includeDeletedItems) {
|
||||||
sql += " AND itemID NOT IN (SELECT itemID FROM deletedItems)";
|
sql += " AND itemID NOT IN (SELECT itemID FROM deletedItems)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var children = yield Zotero.DB.queryAsync(sql, this.id);
|
var children = yield Zotero.DB.queryAsync(sql, this.id);
|
||||||
|
children.sort(function (a, b) {
|
||||||
|
if (a.name === null || b.name === null) return 0;
|
||||||
|
return Zotero.localeCompare(a.name, b.name)
|
||||||
|
});
|
||||||
|
|
||||||
for(var i=0, len=children.length; i<len; i++) {
|
for(var i=0, len=children.length; i<len; i++) {
|
||||||
// This seems to not work without parseInt() even though
|
// This seems to not work without parseInt() even though
|
||||||
|
|
|
@ -13,13 +13,29 @@ describe("Zotero.Collections", function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should get all collections in a library in recursive mode", function* () {
|
it("should get all collections in a library in recursive mode", function* () {
|
||||||
var col1 = yield createDataObject('collection');
|
yield createDataObject('collection', { libraryID: (yield getGroup()).libraryID });
|
||||||
var col2 = yield createDataObject('collection');
|
|
||||||
var col3 = yield createDataObject('collection', { parentID: col2.id });
|
var libraryID = Zotero.Libraries.userLibraryID;
|
||||||
var cols = yield Zotero.Collections.getByLibrary(Zotero.Libraries.userLibraryID, true);
|
var col1 = yield createDataObject('collection', { name: "C" });
|
||||||
assert.isAbove(cols.length, 2);
|
var col2 = yield createDataObject('collection', { name: "A" });
|
||||||
assert.includeMembers(cols.map(col => col.id), [col1.id, col2.id, col3.id]);
|
var col3 = yield createDataObject('collection', { name: "D", parentID: col2.id });
|
||||||
assert.ok(cols.every(col => col.libraryID == Zotero.Libraries.userLibraryID));
|
var col4 = yield createDataObject('collection', { name: "B", parentID: col2.id });
|
||||||
|
var col5 = yield createDataObject('collection', { name: "E", parentID: col2.id });
|
||||||
|
var col6 = yield createDataObject('collection', { name: "G", parentID: col3.id });
|
||||||
|
var col7 = yield createDataObject('collection', { name: "F", parentID: col3.id });
|
||||||
|
var cols = yield Zotero.Collections.getByLibrary(libraryID, true);
|
||||||
|
assert.isAbove(cols.length, 6);
|
||||||
|
var ids = cols.map(col => col.id);
|
||||||
|
assert.includeMembers(
|
||||||
|
ids, [col1.id, col2.id, col3.id, col4.id, col5.id, col6.id, col7.id]
|
||||||
|
);
|
||||||
|
assert.isBelow(ids.indexOf(col2.id), ids.indexOf(col4.id), "A before child B");
|
||||||
|
assert.isBelow(ids.indexOf(col4.id), ids.indexOf(col3.id), "B before D");
|
||||||
|
assert.isBelow(ids.indexOf(col3.id), ids.indexOf(col7.id), "D before child F");
|
||||||
|
assert.isBelow(ids.indexOf(col7.id), ids.indexOf(col6.id), "F before G");
|
||||||
|
assert.isBelow(ids.indexOf(col6.id), ids.indexOf(col5.id), "G before D sibling E");
|
||||||
|
assert.isBelow(ids.indexOf(col5.id), ids.indexOf(col1.id), "E before A sibling C");
|
||||||
|
assert.ok(cols.every(col => col.libraryID == libraryID));
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue