www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit a452af6c3a3a2f007510fbb8bd507ccc65c1177f
parent 984789d304179a75edbe5d0e185d0fd88da0cbe7
Author: Dan Stillman <dstillman@zotero.org>
Date:   Tue, 21 Jul 2015 00:44:38 -0400

Sort descendant collections alphabetically in advanced search window

https://forums.zotero.org/discussion/50679/

Diffstat:
Mchrome/content/zotero/bindings/zoterosearch.xml | 234++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mchrome/content/zotero/xpcom/data/collection.js | 8++++++--
Mtest/tests/collectionsTest.js | 30+++++++++++++++++++++++-------
3 files changed, 146 insertions(+), 126 deletions(-)

diff --git a/chrome/content/zotero/bindings/zoterosearch.xml b/chrome/content/zotero/bindings/zoterosearch.xml @@ -405,130 +405,130 @@ ]]> </constructor> <method name="onConditionSelected"> - <body> - <![CDATA[ - // Skip if correct condition already selected - if (this.id('conditionsmenu').value==this.selectedCondition){ - 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)) + <body><![CDATA[ + return Zotero.spawn(function* () { + // Skip if correct condition already selected + if (this.id('conditionsmenu').value==this.selectedCondition){ + 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++) { - selectThis = 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; + } } - } - operatorsList.selectedIndex = selectThis; - - // 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 += ' '; + operatorsList.selectedIndex = selectThis; + + // 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 = 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 += '- '; } - indent += '- '; + rows.push([indent + cols[i].name, 'C' + cols[i].key]); } - rows.push([indent + cols[i].name, 'C' + cols[i].key]); - } - this.createValueMenu(rows); - break; - - 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 '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(); + this.createValueMenu(rows); + break; - // 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) + 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); }); - } - 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; - 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; - } + 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; - // Textbox - else { - // If switching from menu to textbox, clear value - if (this.id('valuefield').hidden){ - this.id('valuefield').value = ''; + default: + if (operatorsList.value=='isInTheLast') + { + this.id('value-date-age').value = this.value; } - // If switching between textbox conditions, get loaded value for new one + + // Textbox else { - this.id('valuefield').value = this.value; + // If switching from menu to textbox, clear value + if (this.id('valuefield').hidden){ + this.id('valuefield').value = ''; + } + // If switching between textbox conditions, get loaded value for new one + else { + this.id('valuefield').value = this.value; + } + + // Update field drop-down if applicable + this.id('valuefield').update(conditionsMenu.value, this.mode); } - - // Update field drop-down if applicable - this.id('valuefield').update(conditionsMenu.value, this.mode); - } - } - - this.onOperatorSelected(); - ]]> - </body> + } + + this.onOperatorSelected(); + }.bind(this)); + ]]></body> </method> <method name="onOperatorSelected"> <body> @@ -597,8 +597,8 @@ <method name="initWithParentAndCondition"> <parameter name="parent"/> <parameter name="condition"/> - <body> - <![CDATA[ + <body><![CDATA[ + return Zotero.spawn(function* () { this.parent = parent; this.conditionID = condition['id']; @@ -638,11 +638,11 @@ this.dontupdate = false; } - this.onConditionSelected(); + yield this.onConditionSelected(); this.id('conditionsmenu').focus(); - ]]> - </body> + }.bind(this)); + ]]></body> </method> <!-- Gets the value from the field and updates the associated search condition --> <method name="updateSearch"> diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js @@ -690,17 +690,21 @@ Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (re // 0 == collection // 1 == item - var sql = 'SELECT collectionID AS id, ' + var sql = 'SELECT collectionID AS id, collectionName AS name, ' + "0 AS type, collectionName AS collectionName, key " + 'FROM collections WHERE parentCollectionID=?1'; 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'; if (!includeDeletedItems) { sql += " AND itemID NOT IN (SELECT itemID FROM deletedItems)"; } } 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++) { // This seems to not work without parseInt() even though diff --git a/test/tests/collectionsTest.js b/test/tests/collectionsTest.js @@ -13,13 +13,29 @@ describe("Zotero.Collections", function () { }) it("should get all collections in a library in recursive mode", function* () { - var col1 = yield createDataObject('collection'); - var col2 = yield createDataObject('collection'); - var col3 = yield createDataObject('collection', { parentID: col2.id }); - var cols = yield Zotero.Collections.getByLibrary(Zotero.Libraries.userLibraryID, true); - assert.isAbove(cols.length, 2); - assert.includeMembers(cols.map(col => col.id), [col1.id, col2.id, col3.id]); - assert.ok(cols.every(col => col.libraryID == Zotero.Libraries.userLibraryID)); + yield createDataObject('collection', { libraryID: (yield getGroup()).libraryID }); + + var libraryID = Zotero.Libraries.userLibraryID; + var col1 = yield createDataObject('collection', { name: "C" }); + var col2 = yield createDataObject('collection', { name: "A" }); + var col3 = yield createDataObject('collection', { name: "D", parentID: col2.id }); + 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)); }) })