Make various collection methods synchronous

- Collection::getDescendents()
- Collections.getByLibrary()
- Collections.getByParent()

And various things that depend on those. (View with -w.)
This commit is contained in:
Dan Stillman 2016-03-25 18:40:47 -04:00
parent 7dfb62b8fc
commit 15a9fd5494
11 changed files with 275 additions and 237 deletions

View file

@ -401,128 +401,126 @@
</constructor> </constructor>
<method name="onConditionSelected"> <method name="onConditionSelected">
<body><![CDATA[ <body><![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 conditionsMenu = this.id('conditionsmenu'); var operatorsList = this.id('operatorsmenu');
var operatorsList = this.id('operatorsmenu');
this.selectedCondition = conditionsMenu.value;
this.selectedCondition = conditionsMenu.value; this.selectedOperator = operatorsList.value;
this.selectedOperator = operatorsList.value;
var condition = Zotero.SearchConditions.get(conditionsMenu.value);
var condition = Zotero.SearchConditions.get(conditionsMenu.value); var operators = condition['operators'];
var operators = condition['operators'];
// Display appropriate operators for condition
// Display appropriate operators for condition var selectThis;
var selectThis; for(var i = 0, len = operatorsList.firstChild.childNodes.length; i < len; i++)
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))
{ {
var val = operatorsList.firstChild.childNodes[i].getAttribute('value'); selectThis = i;
var hidden = !operators[val]; }
operatorsList.firstChild.childNodes[i].setAttribute('hidden', hidden); }
if (!hidden && (selectThis == null || this.selectedOperator == val)) operatorsList.selectedIndex = selectThis;
{
selectThis = i; // 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.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]);
} }
} this.createValueMenu(rows);
operatorsList.selectedIndex = selectThis; break;
// Generate drop-down menu instead of textbox for certain conditions case 'savedSearch':
switch (conditionsMenu.value){ var rows = [];
case 'collection': var libraryID = this.parent.search.libraryID;
var rows = []; var searches = Zotero.Searches.getAll(libraryID);
for (var i in searches) {
var libraryID = this.parent.search.libraryID; if (searches[i].id != this.parent.search.id) {
var cols = yield Zotero.Collections.getByLibrary(libraryID, true); rows.push([searches[i].name, 'S' + searches[i].key]);
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; this.createValueMenu(rows);
break;
case 'itemType':
var t = Zotero.ItemTypes.getTypes();
case 'savedSearch': // Sort by localized name
var rows = []; var types = [];
var libraryID = this.parent.search.libraryID; for (var i=0; i<t.length; i++) {
var searches = Zotero.Searches.getAll(libraryID); types.push({
for (var i in searches) { id: t[i].id,
if (searches[i].id != this.parent.search.id) { name: t[i].name,
rows.push([searches[i].name, 'S' + searches[i].key]); localized: Zotero.ItemTypes.getLocalizedString(t[i].id)
}
}
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) { var collation = Zotero.getLocaleCollation();
types[i][0] = types[i].localized; types.sort(function(a, b) {
types[i][1] = types[i].name; return collation.compareString(1, a.localized, b.localized);
delete types[i]['name']; });
delete types[i]['id'];
}
this.createValueMenu(types);
break;
case 'fileTypeID': for (var i in types) {
var types = Zotero.FileTypes.getTypes(); types[i][0] = types[i].localized;
for (var i in types) { types[i][1] = types[i].name;
types[i][0] = Zotero.getString('fileTypes.' + types[i]['name']); delete types[i]['name'];
types[i][1] = types[i]['id']; delete types[i]['id'];
delete types[i]['name']; }
delete types[i]['id']; this.createValueMenu(types);
} break;
this.createValueMenu(types);
break;
default:
if (operatorsList.value=='isInTheLast')
{
this.id('value-date-age').value = this.value;
}
// Textbox
else {
// 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);
}
}
this.onOperatorSelected(); case 'fileTypeID':
}.bind(this)); 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;
}
// Textbox
else {
// 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);
}
}
this.onOperatorSelected();
]]></body> ]]></body>
</method> </method>
<method name="onOperatorSelected"> <method name="onOperatorSelected">
@ -593,50 +591,48 @@
<parameter name="parent"/> <parameter name="parent"/>
<parameter name="condition"/> <parameter name="condition"/>
<body><![CDATA[ <body><![CDATA[
return Zotero.spawn(function* () { this.parent = parent;
this.parent = parent; this.conditionID = condition['id'];
this.conditionID = condition['id'];
if(this.parent.search)
{
this.dontupdate = true; //so that the search doesn't get updated while we are creating controls.
var prefix = '';
if(this.parent.search) // Handle special conditions
{ switch (condition.condition) {
this.dontupdate = true; //so that the search doesn't get updated while we are creating controls. case 'savedSearch':
var prefix = ''; prefix = 'S';
break;
// Handle special conditions case 'collection':
switch (condition.condition) { prefix = 'C';
case 'savedSearch': break;
prefix = 'S';
break;
case 'collection':
prefix = 'C';
break;
}
this.id('conditionsmenu').value = condition.condition;
// Convert datetimes from UTC to localtime
if ((condition['condition']=='accessDate' ||
condition['condition']=='dateAdded' ||
condition['condition']=='dateModified') &&
Zotero.Date.isSQLDateTime(condition['value'])){
condition['value'] =
Zotero.Date.dateToSQL(Zotero.Date.sqlToDate(condition['value'], true));
}
this.mode = condition['mode'];
this.id('operatorsmenu').value = condition['operator'];
this.value = prefix +
(condition.value ? condition.value : '');
this.dontupdate = false;
} }
yield this.onConditionSelected(); this.id('conditionsmenu').value = condition.condition;
this.id('conditionsmenu').focus(); // Convert datetimes from UTC to localtime
}.bind(this)); if ((condition['condition']=='accessDate' ||
condition['condition']=='dateAdded' ||
condition['condition']=='dateModified') &&
Zotero.Date.isSQLDateTime(condition['value'])){
condition['value'] =
Zotero.Date.dateToSQL(Zotero.Date.sqlToDate(condition['value'], true));
}
this.mode = condition['mode'];
this.id('operatorsmenu').value = condition['operator'];
this.value = prefix +
(condition.value ? condition.value : '');
this.dontupdate = false;
}
this.onConditionSelected();
this.id('conditionsmenu').focus();
]]></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 -->

View file

@ -304,7 +304,7 @@ var Zotero_File_Interface = new function() {
let leafName = translation.location.leafName; let leafName = translation.location.leafName;
collectionName = (translation.location.isDirectory() || leafName.indexOf(".") === -1 ? leafName collectionName = (translation.location.isDirectory() || leafName.indexOf(".") === -1 ? leafName
: leafName.substr(0, leafName.lastIndexOf("."))); : leafName.substr(0, leafName.lastIndexOf(".")));
let allCollections = yield Zotero.Collections.getByLibrary(libraryID); let allCollections = Zotero.Collections.getByLibrary(libraryID);
for(var i=0; i<allCollections.length; i++) { for(var i=0; i<allCollections.length; i++) {
if(allCollections[i].name == collectionName) { if(allCollections[i].name == collectionName) {
collectionName += " "+(new Date()).toLocaleString(); collectionName += " "+(new Date()).toLocaleString();

View file

@ -46,12 +46,12 @@ Zotero.API = {
switch (params.scopeObject) { switch (params.scopeObject) {
case 'collections': case 'collections':
if (params.scopeObjectKey) { if (params.scopeObjectKey) {
var col = yield Zotero.Collections.getByLibraryAndKeyAsync( var col = Zotero.Collections.getByLibraryAndKeyAsync(
params.libraryID, params.scopeObjectKey params.libraryID, params.scopeObjectKey
); );
} }
else { else {
var col = yield Zotero.Collections.getAsync(params.scopeObjectID); var col = Zotero.Collections.get(params.scopeObjectID);
} }
if (!col) { if (!col) {
throw new Error('Invalid collection ID or key'); throw new Error('Invalid collection ID or key');

View file

@ -1153,10 +1153,10 @@ Zotero.CollectionTreeView.prototype._expandRow = Zotero.Promise.coroutine(functi
} }
if (isLibrary) { if (isLibrary) {
var collections = yield Zotero.Collections.getByLibrary(libraryID, treeRow.ref.id); var collections = Zotero.Collections.getByLibrary(libraryID, treeRow.ref.id);
} }
else if (isCollection) { else if (isCollection) {
var collections = yield Zotero.Collections.getByParent(treeRow.ref.id); var collections = Zotero.Collections.getByParent(treeRow.ref.id);
} }
if (isLibrary) { if (isLibrary) {
@ -1549,10 +1549,9 @@ Zotero.CollectionTreeView.prototype.canDropCheck = function (row, orient, dataTr
} }
// Nor in their children // Nor in their children
// TODO: figure out synchronously from tree if (col.hasDescendent('collection', treeRow.ref.id)) {
/*if (yield col.hasDescendent('collection', treeRow.ref.id)) {
return false; return false;
}*/ }
} }
// Dragging a collection to a different library // Dragging a collection to a different library
else { else {
@ -1657,9 +1656,9 @@ Zotero.CollectionTreeView.prototype.canDropCheckAsync = Zotero.Promise.coroutine
return false; return false;
} }
var descendents = yield col.getDescendents(false, 'collection'); var descendents = col.getDescendents(false, 'collection');
for each(var descendent in descendents) { for each(var descendent in descendents) {
descendent = yield Zotero.Collections.getAsync(descendent.id); descendent = Zotero.Collections.get(descendent.id);
// Disallow if linked collection already exists for any subcollections // Disallow if linked collection already exists for any subcollections
// //
// If this is allowed in the future for the root collection, // If this is allowed in the future for the root collection,

View file

@ -242,7 +242,7 @@ Zotero.Collection.prototype._initSave = Zotero.Promise.coroutine(function* (env)
throw new Error('Cannot move collection into itself!'); throw new Error('Cannot move collection into itself!');
} }
if (this.id && (yield this.hasDescendent('collection', newParent.id))) { if (this.id && this.hasDescendent('collection', newParent.id)) {
throw ('Cannot move collection "' + this.name + '" into one of its own descendents'); throw ('Cannot move collection "' + this.name + '" into one of its own descendents');
} }
@ -440,15 +440,15 @@ Zotero.Collection.prototype.hasItem = function(itemID) {
} }
Zotero.Collection.prototype.hasDescendent = Zotero.Promise.coroutine(function* (type, id) { Zotero.Collection.prototype.hasDescendent = function (type, id) {
var descendents = yield this.getDescendents(); var descendents = this.getDescendents();
for (var i=0, len=descendents.length; i<len; i++) { for (var i=0, len=descendents.length; i<len; i++) {
if (descendents[i].type == type && descendents[i].id == id) { if (descendents[i].type == type && descendents[i].id == id) {
return true; return true;
} }
} }
return false; return false;
}); };
/** /**
@ -551,7 +551,7 @@ Zotero.Collection.prototype._eraseData = Zotero.Promise.coroutine(function* (env
var collections = [this.id]; var collections = [this.id];
var descendents = yield this.getDescendents(false, null, true); var descendents = this.getDescendents(false, null, true);
var items = []; var items = [];
var del = []; var del = [];
@ -701,7 +701,6 @@ Zotero.Collection.prototype.toJSON = function (options = {}) {
/** /**
* Returns an array of descendent collections and items * Returns an array of descendent collections and items
* *
* @param {Boolean} [recursive=false] Descend into subcollections
* @param {Boolean} [nested=false] Return multidimensional array with 'children' * @param {Boolean} [nested=false] Return multidimensional array with 'children'
* nodes instead of flat array * nodes instead of flat array
* @param {String} [type] 'item', 'collection', or NULL for both * @param {String} [type] 'item', 'collection', or NULL for both
@ -709,13 +708,11 @@ Zotero.Collection.prototype.toJSON = function (options = {}) {
* @return {Promise<Object[]>} - A promise for an array of objects with 'id', 'key', * @return {Promise<Object[]>} - A promise for an array of objects with 'id', 'key',
* 'type' ('item' or 'collection'), 'parent', and, if collection, 'name' and the nesting 'level' * 'type' ('item' or 'collection'), 'parent', and, if collection, 'name' and the nesting 'level'
*/ */
Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (recursive, nested, type, includeDeletedItems, level) { Zotero.Collection.prototype.getDescendents = function (nested, type, includeDeletedItems, level) {
if (!this.id) { if (!this.id) {
throw new Error('Cannot be called on an unsaved item'); throw new Error('Cannot be called on an unsaved item');
} }
var toReturn = [];
if (!level) { if (!level) {
level = 1; level = 1;
} }
@ -726,39 +723,40 @@ Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (re
case 'collection': case 'collection':
break; break;
default: default:
throw ("Invalid type '" + type + "' in Collection.getChildren()"); throw new (`Invalid type '${type}'`);
} }
} }
// 0 == collection var collections = Zotero.Collections.getByParent(this.id);
// 1 == item var children = collections.map(c => ({
var sql = 'SELECT collectionID AS id, collectionName AS name, ' id: c.id,
+ "0 AS type, collectionName AS collectionName, key " name: c.name,
+ 'FROM collections WHERE parentCollectionID=?1'; type: 0,
key: c.key
}));
if (!type || type == 'item') { if (!type || type == 'item') {
sql += ' UNION SELECT itemID AS id, NULL AS name, 1 AS type, NULL AS collectionName, key ' let items = this.getChildItems(false, includeDeletedItems);
+ 'FROM collectionItems JOIN items USING (itemID) WHERE collectionID=?1'; children = children.concat(items.map(i => ({
if (!includeDeletedItems) { id: i.id,
sql += " AND itemID NOT IN (SELECT itemID FROM deletedItems)"; name: null,
} type: 1,
key: i.key
})));
} }
var children = yield Zotero.DB.queryAsync(sql, this.id);
children.sort(function (a, b) { children.sort(function (a, b) {
if (a.name === null || b.name === null) return 0; if (a.name === null || b.name === null) return 0;
return Zotero.localeCompare(a.name, b.name) return Zotero.localeCompare(a.name, b.name)
}); });
var toReturn = [];
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 switch (children[i].type) {
// typeof children[i]['type'] == 'number' and
// children[i]['type'] === parseInt(children[i]['type']),
// which sure seems like a bug to me
switch (parseInt(children[i].type)) {
case 0: case 0:
if (!type || type=='collection') { if (!type || type=='collection') {
toReturn.push({ toReturn.push({
id: children[i].id, id: children[i].id,
name: children[i].collectionName, name: children[i].name,
key: children[i].key, key: children[i].key,
type: 'collection', type: 'collection',
level: level, level: level,
@ -766,19 +764,17 @@ Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (re
}); });
} }
if (recursive) { let child = this.ObjectsClass.get(children[i].id);
let child = yield this.ObjectsClass.getAsync(children[i].id); let descendents = child.getDescendents(
let descendents = yield child.getChildren( nested, type, includeDeletedItems, level + 1
true, nested, type, includeDeletedItems, level+1 );
);
if (nested) {
if (nested) { toReturn[toReturn.length-1].children = descendents;
toReturn[toReturn.length-1].children = descendents; }
} else {
else { for (var j=0, len2=descendents.length; j<len2; j++) {
for (var j=0, len2=descendents.length; j<len2; j++) { toReturn.push(descendents[j]);
toReturn.push(descendents[j]);
}
} }
} }
break; break;
@ -797,17 +793,7 @@ Zotero.Collection.prototype.getChildren = Zotero.Promise.coroutine(function* (re
} }
return toReturn; return toReturn;
}); };
/**
* Alias for the recursive mode of getChildren()
*
* @return {Promise}
*/
Zotero.Collection.prototype.getDescendents = function (nested, type, includeDeletedItems) {
return this.getChildren(true, nested, type, includeDeletedItems);
}
/** /**

View file

@ -62,7 +62,7 @@ Zotero.Collections = function() {
* *
* @param {Integer} libraryID * @param {Integer} libraryID
* @param {Boolean} [recursive=false] * @param {Boolean} [recursive=false]
* @return {Promise<Zotero.Collection[]>} * @return {Zotero.Collection[]}
*/ */
this.getByLibrary = function (libraryID, recursive) { this.getByLibrary = function (libraryID, recursive) {
return _getByContainer(libraryID, null, recursive); return _getByContainer(libraryID, null, recursive);
@ -74,24 +74,26 @@ Zotero.Collections = function() {
* *
* @param {Integer} parentCollectionID * @param {Integer} parentCollectionID
* @param {Boolean} [recursive=false] * @param {Boolean} [recursive=false]
* @return {Promise<Zotero.Collection[]>} * @return {Zotero.Collection[]}
*/ */
this.getByParent = function (parentCollectionID, recursive) { this.getByParent = function (parentCollectionID, recursive) {
return _getByContainer(null, parentCollectionID, recursive); return _getByContainer(null, parentCollectionID, recursive);
} }
var _getByContainer = Zotero.Promise.coroutine(function* (libraryID, parentID, recursive) { var _getByContainer = function (libraryID, parentID, recursive) {
let children; let children = [];
if (parentID) { if (parentID) {
let parent = Zotero.Collections.get(parentID); let parent = Zotero.Collections.get(parentID);
children = parent.getChildCollections(); children = parent.getChildCollections();
} else if (libraryID) { } else if (libraryID) {
let sql = "SELECT collectionID AS id FROM collections " for (let id in this._objectCache) {
+ "WHERE libraryID=? AND parentCollectionID IS NULL"; let c = this._objectCache[id];
let ids = yield Zotero.DB.columnQueryAsync(sql, [libraryID]); if (c.libraryID == libraryID && !c.parentKey) {
children = yield this.getAsync(ids); children.push(c);
}
}
} else { } else {
throw new Error("Either library ID or parent collection ID must be provided"); throw new Error("Either library ID or parent collection ID must be provided");
} }
@ -110,9 +112,9 @@ Zotero.Collections = function() {
var obj = children[i]; var obj = children[i];
toReturn.push(obj); toReturn.push(obj);
var desc = yield obj.getDescendents(false, 'collection'); var desc = obj.getDescendents(false, 'collection');
for (var j in desc) { for (var j in desc) {
var obj2 = yield this.getAsync(desc[j]['id']); var obj2 = this.get(desc[j].id);
if (!obj2) { if (!obj2) {
throw new Error('Collection ' + desc[j] + ' not found'); throw new Error('Collection ' + desc[j] + ' not found');
} }
@ -130,7 +132,7 @@ Zotero.Collections = function() {
} }
return toReturn; return toReturn;
}.bind(this)); }.bind(this);
this.getCollectionsContainingItems = function (itemIDs, asIDs) { this.getCollectionsContainingItems = function (itemIDs, asIDs) {

View file

@ -2315,7 +2315,7 @@ Zotero.Translate.Export.prototype._prepareTranslation = Zotero.Promise.coroutine
getCollections = configOptions.getCollections || false; getCollections = configOptions.getCollections || false;
switch (this._export.type) { switch (this._export.type) {
case 'collection': case 'collection':
yield this._itemGetter.setCollection(this._export.collection, getCollections); this._itemGetter.setCollection(this._export.collection, getCollections);
break; break;
case 'items': case 'items':
this._itemGetter.setItems(this._export.items); this._itemGetter.setItems(this._export.items);

View file

@ -657,13 +657,13 @@ Zotero.Translate.ItemGetter.prototype = {
this.numItems = this._itemsLeft.length; this.numItems = this._itemsLeft.length;
}, },
"setCollection": Zotero.Promise.coroutine(function* (collection, getChildCollections) { "setCollection": function (collection, getChildCollections) {
// get items in this collection // get items in this collection
var items = new Set(collection.getChildItems()); var items = new Set(collection.getChildItems());
if(getChildCollections) { if(getChildCollections) {
// get child collections // get child collections
this._collectionsLeft = yield Zotero.Collections.getByParent(collection.id, true); this._collectionsLeft = Zotero.Collections.getByParent(collection.id, true);
// get items in child collections // get items in child collections
for (let collection of this._collectionsLeft) { for (let collection of this._collectionsLeft) {
@ -674,13 +674,13 @@ Zotero.Translate.ItemGetter.prototype = {
this._itemsLeft = Array.from(items.values()); this._itemsLeft = Array.from(items.values());
this.numItems = this._itemsLeft.length; this.numItems = this._itemsLeft.length;
}), },
"setAll": Zotero.Promise.coroutine(function* (libraryID, getChildCollections) { "setAll": Zotero.Promise.coroutine(function* (libraryID, getChildCollections) {
this._itemsLeft = yield Zotero.Items.getAll(libraryID, true); this._itemsLeft = yield Zotero.Items.getAll(libraryID, true);
if(getChildCollections) { if(getChildCollections) {
this._collectionsLeft = yield Zotero.Collections.getByLibrary(libraryID, true); this._collectionsLeft = Zotero.Collections.getByLibrary(libraryID, true);
} }
this.numItems = this._itemsLeft.length; this.numItems = this._itemsLeft.length;

View file

@ -200,4 +200,57 @@ describe("Zotero.Collection", function() {
assert.lengthOf(collection.getChildItems(false, true), 1); assert.lengthOf(collection.getChildItems(false, true), 1);
}) })
}) })
describe("#getDescendents()", function () {
var collection0, collection1, collection2, collection3, item1, item2, item3;
before(function* () {
collection0 = yield createDataObject('collection');
item1 = yield createDataObject('item', { collections: [collection0.id] });
collection1 = yield createDataObject('collection', { parentKey: collection0.key });
item2 = yield createDataObject('item', { collections: [collection1.id] });
collection2 = yield createDataObject('collection', { parentKey: collection1.key });
collection3 = yield createDataObject('collection', { parentKey: collection1.key });
item3 = yield createDataObject('item', { collections: [collection2.id] });
item3.deleted = true;
yield item3.saveTx();
});
it("should return a flat array of collections and items", function* () {
var desc = collection0.getDescendents();
assert.lengthOf(desc, 5);
assert.sameMembers(
desc.map(x => x.type + ':' + x.id + ':' + (x.name || '') + ':' + x.parent),
[
'item:' + item1.id + '::' + collection0.id,
'item:' + item2.id + '::' + collection1.id,
'collection:' + collection1.id + ':' + collection1.name + ':' + collection0.id,
'collection:' + collection2.id + ':' + collection2.name + ':' + collection1.id,
'collection:' + collection3.id + ':' + collection3.name + ':' + collection1.id
]
);
});
it("should return nested arrays of collections and items", function* () {
var desc = collection0.getDescendents(true);
assert.lengthOf(desc, 2);
assert.sameMembers(
desc.map(x => x.type + ':' + x.id + ':' + (x.name || '') + ':' + x.parent),
[
'item:' + item1.id + '::' + collection0.id,
'collection:' + collection1.id + ':' + collection1.name + ':' + collection0.id,
]
);
var c = desc[0].type == 'collection' ? desc[0] : desc[1];
assert.lengthOf(c.children, 3);
assert.sameMembers(
c.children.map(x => x.type + ':' + x.id + ':' + (x.name || '') + ':' + x.parent),
[
'item:' + item2.id + '::' + collection1.id,
'collection:' + collection2.id + ':' + collection2.name + ':' + collection1.id,
'collection:' + collection3.id + ':' + collection3.name + ':' + collection1.id
]
);
});
});
}) })

View file

@ -4,7 +4,7 @@ describe("Zotero.Collections", function () {
var col1 = yield createDataObject('collection'); var col1 = yield createDataObject('collection');
var col2 = yield createDataObject('collection'); var col2 = yield createDataObject('collection');
var col3 = yield createDataObject('collection', { parentID: col2.id }); var col3 = yield createDataObject('collection', { parentID: col2.id });
var cols = yield Zotero.Collections.getByLibrary(Zotero.Libraries.userLibraryID); var cols = Zotero.Collections.getByLibrary(Zotero.Libraries.userLibraryID);
assert.isAbove(cols.length, 1); assert.isAbove(cols.length, 1);
assert.includeMembers(cols.map(col => col.id), [col1.id, col2.id]); assert.includeMembers(cols.map(col => col.id), [col1.id, col2.id]);
assert.ok(cols.every(col => assert.ok(cols.every(col =>
@ -23,7 +23,7 @@ describe("Zotero.Collections", function () {
var col5 = yield createDataObject('collection', { name: "E", parentID: col2.id }); var col5 = yield createDataObject('collection', { name: "E", parentID: col2.id });
var col6 = yield createDataObject('collection', { name: "G", parentID: col3.id }); var col6 = yield createDataObject('collection', { name: "G", parentID: col3.id });
var col7 = yield createDataObject('collection', { name: "F", parentID: col3.id }); var col7 = yield createDataObject('collection', { name: "F", parentID: col3.id });
var cols = yield Zotero.Collections.getByLibrary(libraryID, true); var cols = Zotero.Collections.getByLibrary(libraryID, true);
assert.isAbove(cols.length, 6); assert.isAbove(cols.length, 6);
var ids = cols.map(col => col.id); var ids = cols.map(col => col.id);
assert.includeMembers( assert.includeMembers(
@ -44,8 +44,8 @@ describe("Zotero.Collections", function () {
var col1 = yield createDataObject('collection'); var col1 = yield createDataObject('collection');
var col2 = yield createDataObject('collection'); var col2 = yield createDataObject('collection');
var col3 = yield createDataObject('collection', { parentID: col2.id }); var col3 = yield createDataObject('collection', { parentID: col2.id });
assert.lengthOf((yield Zotero.Collections.getByParent(col1.id)), 0); assert.lengthOf(Zotero.Collections.getByParent(col1.id), 0);
var cols = yield Zotero.Collections.getByParent(col2.id); var cols = Zotero.Collections.getByParent(col2.id);
assert.lengthOf(cols, 1); assert.lengthOf(cols, 1);
assert.sameMembers(cols.map(col => col.id), [col3.id]); assert.sameMembers(cols.map(col => col.id), [col3.id]);
}) })
@ -55,8 +55,8 @@ describe("Zotero.Collections", function () {
var col2 = yield createDataObject('collection'); var col2 = yield createDataObject('collection');
var col3 = yield createDataObject('collection', { parentID: col2.id }); var col3 = yield createDataObject('collection', { parentID: col2.id });
var col4 = yield createDataObject('collection', { parentID: col3.id }); var col4 = yield createDataObject('collection', { parentID: col3.id });
assert.lengthOf((yield Zotero.Collections.getByParent(col1.id)), 0); assert.lengthOf(Zotero.Collections.getByParent(col1.id), 0);
var cols = yield Zotero.Collections.getByParent(col2.id, true); var cols = Zotero.Collections.getByParent(col2.id, true);
assert.lengthOf(cols, 2); assert.lengthOf(cols, 2);
assert.includeMembers(cols.map(col => col.id), [col3.id, col4.id]); assert.includeMembers(cols.map(col => col.id), [col3.id, col4.id]);
}) })

View file

@ -16,7 +16,9 @@ describe("Zotero_File_Interface", function() {
testFile.append("allTypesAndFields.js"); testFile.append("allTypesAndFields.js");
yield win.Zotero_File_Interface.importFile(testFile); yield win.Zotero_File_Interface.importFile(testFile);
let importedCollection = yield Zotero.Collections.getByLibrary(Zotero.Libraries.userLibraryID).filter(x => x.name == 'allTypesAndFields'); let importedCollection = Zotero.Collections.getByLibrary(
Zotero.Libraries.userLibraryID
).filter(x => x.name == 'allTypesAndFields');
assert.equal(importedCollection.length, 1); assert.equal(importedCollection.length, 1);
let childItems = importedCollection[0].getChildItems(); let childItems = importedCollection[0].getChildItems();
let savedItems = {}; let savedItems = {};