Saved search fixes
- Fix saved search editing - Refresh items list on search change - Generate correct conditions array for search JSON
This commit is contained in:
parent
62f3177d36
commit
b7b246e741
|
@ -222,15 +222,6 @@
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="save">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
this.updateSearch();
|
|
||||||
return this.search.save();
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="handleKeyPress">
|
<method name="handleKeyPress">
|
||||||
<parameter name="event"/>
|
<parameter name="event"/>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
var itemsView;
|
var itemsView;
|
||||||
var collectionsView;
|
var collectionsView;
|
||||||
var io;
|
var io;
|
||||||
|
@ -50,7 +52,11 @@ function doAccept()
|
||||||
{
|
{
|
||||||
document.getElementById('search-box').search.name = document.getElementById('search-name').value;
|
document.getElementById('search-box').search.name = document.getElementById('search-name').value;
|
||||||
try {
|
try {
|
||||||
io.dataOut = document.getElementById('search-box').save();
|
let searchBox = document.getElementById('search-box');
|
||||||
|
searchBox.updateSearch();
|
||||||
|
io.dataOut = {
|
||||||
|
json: searchBox.search.toJSON()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
Zotero.debug(e, 1);
|
Zotero.debug(e, 1);
|
||||||
|
|
|
@ -55,7 +55,7 @@ Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
|
||||||
|
|
||||||
this._unregisterID = Zotero.Notifier.registerObserver(
|
this._unregisterID = Zotero.Notifier.registerObserver(
|
||||||
this,
|
this,
|
||||||
['item', 'collection-item', 'item-tag', 'share-items', 'bucket', 'feedItem'],
|
['item', 'collection-item', 'item-tag', 'share-items', 'bucket', 'feedItem', 'search'],
|
||||||
'itemTreeView',
|
'itemTreeView',
|
||||||
50
|
50
|
||||||
);
|
);
|
||||||
|
@ -348,8 +348,8 @@ Zotero.ItemTreeView.prototype.refresh = Zotero.serial(Zotero.Promise.coroutine(f
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var newItems = yield this.collectionTreeRow.getItems();
|
|
||||||
Zotero.CollectionTreeCache.clear();
|
Zotero.CollectionTreeCache.clear();
|
||||||
|
var newItems = yield this.collectionTreeRow.getItems();
|
||||||
|
|
||||||
if (!this.selection.selectEventsSuppressed) {
|
if (!this.selection.selectEventsSuppressed) {
|
||||||
var unsuppress = this.selection.selectEventsSuppressed = true;
|
var unsuppress = this.selection.selectEventsSuppressed = true;
|
||||||
|
@ -464,6 +464,14 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == 'search' && action == 'modify') {
|
||||||
|
// TODO: Only refresh on condition change (not currently available in extraData)
|
||||||
|
yield this.refresh();
|
||||||
|
this.sort();
|
||||||
|
this._treebox.invalidate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear item type icon and tag colors when a tag is added to or removed from an item
|
// Clear item type icon and tag colors when a tag is added to or removed from an item
|
||||||
if (type == 'item-tag') {
|
if (type == 'item-tag') {
|
||||||
// TODO: Only update if colored tag changed?
|
// TODO: Only update if colored tag changed?
|
||||||
|
@ -757,7 +765,7 @@ Zotero.ItemTreeView.prototype.notify = Zotero.Promise.coroutine(function* (actio
|
||||||
}
|
}
|
||||||
else if(type == 'item' && action == 'add')
|
else if(type == 'item' && action == 'add')
|
||||||
{
|
{
|
||||||
let items = yield Zotero.Items.getAsync(ids);
|
let items = Zotero.Items.get(ids);
|
||||||
|
|
||||||
// In some modes, just re-run search
|
// In some modes, just re-run search
|
||||||
if (collectionTreeRow.isSearch() || collectionTreeRow.isTrash() || collectionTreeRow.isUnfiled()) {
|
if (collectionTreeRow.isSearch() || collectionTreeRow.isTrash() || collectionTreeRow.isUnfiled()) {
|
||||||
|
|
|
@ -447,6 +447,7 @@ Zotero.Search.prototype.removeCondition = function (searchConditionID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this._conditions[searchConditionID];
|
delete this._conditions[searchConditionID];
|
||||||
|
this._maxSearchConditionID--;
|
||||||
this._markFieldChange('conditions', this._conditions);
|
this._markFieldChange('conditions', this._conditions);
|
||||||
this._changed.conditions = true;
|
this._changed.conditions = true;
|
||||||
}
|
}
|
||||||
|
@ -827,6 +828,7 @@ Zotero.Search.prototype.fromJSON = function (json) {
|
||||||
}
|
}
|
||||||
this.name = json.name;
|
this.name = json.name;
|
||||||
|
|
||||||
|
Object.keys(this.getConditions()).forEach(id => this.removeCondition(0));
|
||||||
for (let i = 0; i < json.conditions.length; i++) {
|
for (let i = 0; i < json.conditions.length; i++) {
|
||||||
let condition = json.conditions[i];
|
let condition = json.conditions[i];
|
||||||
this.addCondition(
|
this.addCondition(
|
||||||
|
@ -851,7 +853,8 @@ Zotero.Search.prototype.toJSON = function (options = {}) {
|
||||||
obj.key = this.key;
|
obj.key = this.key;
|
||||||
obj.version = this.version;
|
obj.version = this.version;
|
||||||
obj.name = this.name;
|
obj.name = this.name;
|
||||||
obj.conditions = this.getConditions();
|
var conditions = this.getConditions();
|
||||||
|
obj.conditions = Object.keys(conditions).map(x => conditions[x]);
|
||||||
|
|
||||||
return this._postToJSON(env);
|
return this._postToJSON(env);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1899,10 +1899,7 @@ var ZoteroPane = new function()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let s = new Zotero.Search();
|
let s = row.ref.clone();
|
||||||
s.id = row.ref.id;
|
|
||||||
yield s.loadPrimaryData();
|
|
||||||
yield s.loadConditions();
|
|
||||||
let groups = [];
|
let groups = [];
|
||||||
// Promises don't work in the modal dialog, so get the group name here, if
|
// Promises don't work in the modal dialog, so get the group name here, if
|
||||||
// applicable, and pass it in. We only need the group that this search belongs
|
// applicable, and pass it in. We only need the group that this search belongs
|
||||||
|
@ -1920,7 +1917,8 @@ var ZoteroPane = new function()
|
||||||
};
|
};
|
||||||
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
window.openDialog('chrome://zotero/content/searchDialog.xul','','chrome,modal',io);
|
||||||
if (io.dataOut) {
|
if (io.dataOut) {
|
||||||
this.onCollectionSelected(); //reload itemsView
|
row.ref.fromJSON(io.dataOut.json);
|
||||||
|
yield row.ref.saveTx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,6 +382,10 @@ function createUnsavedDataObject(objectType, params = {}) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (objectType == 'search') {
|
||||||
|
obj.addCondition('title', 'contains', 'test');
|
||||||
|
}
|
||||||
|
|
||||||
Zotero.Utilities.assignProps(obj, params, allowedParams);
|
Zotero.Utilities.assignProps(obj, params, allowedParams);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
|
@ -232,6 +232,64 @@ describe("Zotero.ItemTreeView", function() {
|
||||||
yield Zotero.Items.erase(items.map(item => item.id));
|
yield Zotero.Items.erase(items.map(item => item.id));
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should update search results when items are added", function* () {
|
||||||
|
var search = createUnsavedDataObject('search');
|
||||||
|
var title = Zotero.Utilities.randomString();
|
||||||
|
search.fromJSON({
|
||||||
|
name: "Test",
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
condition: "title",
|
||||||
|
operator: "is",
|
||||||
|
value: title
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
yield search.saveTx();
|
||||||
|
|
||||||
|
yield waitForItemsLoad(win);
|
||||||
|
assert.equal(zp.itemsView.rowCount, 0);
|
||||||
|
|
||||||
|
// Add an item matching search
|
||||||
|
var item = yield createDataObject('item', { title });
|
||||||
|
|
||||||
|
yield waitForItemsLoad(win);
|
||||||
|
assert.equal(zp.itemsView.rowCount, 1);
|
||||||
|
assert.equal(zp.itemsView.getRowIndexByID(item.id), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should update search results when search conditions are changed", function* () {
|
||||||
|
var search = createUnsavedDataObject('search');
|
||||||
|
var title1 = Zotero.Utilities.randomString();
|
||||||
|
var title2 = Zotero.Utilities.randomString();
|
||||||
|
search.fromJSON({
|
||||||
|
name: "Test",
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
condition: "title",
|
||||||
|
operator: "is",
|
||||||
|
value: title1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
yield search.saveTx();
|
||||||
|
|
||||||
|
yield waitForItemsLoad(win);
|
||||||
|
|
||||||
|
// Add an item that doesn't match search
|
||||||
|
var item = yield createDataObject('item', { title: title2 });
|
||||||
|
yield waitForItemsLoad(win);
|
||||||
|
assert.equal(zp.itemsView.rowCount, 0);
|
||||||
|
|
||||||
|
// Modify conditions to match item
|
||||||
|
search.removeCondition(0);
|
||||||
|
search.addCondition("title", "is", title2);
|
||||||
|
yield search.saveTx();
|
||||||
|
|
||||||
|
yield waitForItemsLoad(win);
|
||||||
|
|
||||||
|
assert.equal(zp.itemsView.rowCount, 1);
|
||||||
|
});
|
||||||
|
|
||||||
it("should remove items from Unfiled Items when added to a collection", function* () {
|
it("should remove items from Unfiled Items when added to a collection", function* () {
|
||||||
var userLibraryID = Zotero.Libraries.userLibraryID;
|
var userLibraryID = Zotero.Libraries.userLibraryID;
|
||||||
|
|
|
@ -147,4 +147,53 @@ describe("Zotero.Search", function() {
|
||||||
assert.deepEqual(matches, [foobarItem.id]);
|
assert.deepEqual(matches, [foobarItem.id]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#toJSON()", function () {
|
||||||
|
it("should output all data", function* () {
|
||||||
|
let s = new Zotero.Search();
|
||||||
|
s.name = "Test";
|
||||||
|
s.addCondition('joinMode', 'any');
|
||||||
|
s.addCondition('fulltextWord', 'contains', 'afsgagsdg');
|
||||||
|
let json = s.toJSON();
|
||||||
|
assert.equal(json.name, "Test");
|
||||||
|
assert.lengthOf(json.conditions, 2);
|
||||||
|
assert.equal(json.conditions[0].condition, 'joinMode');
|
||||||
|
assert.equal(json.conditions[0].operator, 'any');
|
||||||
|
assert.equal(json.conditions[1].condition, 'fulltextWord');
|
||||||
|
assert.equal(json.conditions[1].operator, 'contains');
|
||||||
|
assert.equal(json.conditions[1].value, 'afsgagsdg');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#fromJSON()", function () {
|
||||||
|
it("should update all data", function* () {
|
||||||
|
let s = new Zotero.Search();
|
||||||
|
s.name = "Test";
|
||||||
|
s.addCondition('joinMode', 'any');
|
||||||
|
let json = s.toJSON();
|
||||||
|
json.name = "Test 2";
|
||||||
|
json.conditions = [
|
||||||
|
{
|
||||||
|
condition: 'title',
|
||||||
|
operator: 'contains',
|
||||||
|
value: 'foo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
condition: 'year',
|
||||||
|
operator: 'is',
|
||||||
|
value: '2016'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
s.fromJSON(json);
|
||||||
|
assert.equal(s.name, "Test 2");
|
||||||
|
var conditions = s.getConditions();
|
||||||
|
assert.lengthOf(Object.keys(conditions), 2);
|
||||||
|
assert.equal(conditions["0"].condition, 'title');
|
||||||
|
assert.equal(conditions["0"].operator, 'contains');
|
||||||
|
assert.equal(conditions["0"].value, 'foo');
|
||||||
|
assert.equal(conditions["1"].condition, 'year');
|
||||||
|
assert.equal(conditions["1"].operator, 'is');
|
||||||
|
assert.equal(conditions["1"].value, '2016');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -449,7 +449,7 @@ describe("Zotero.Sync.Data.Engine", function () {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'search':
|
case 'search':
|
||||||
assert.typeOf(cached.data.conditions, 'object');
|
assert.isArray(cached.data.conditions);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,4 +290,24 @@ describe("ZoteroPane", function() {
|
||||||
assert.equal(cv.getSelectedLibraryID(), userLibraryID);
|
assert.equal(cv.getSelectedLibraryID(), userLibraryID);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#editSelectedCollection()", function () {
|
||||||
|
it("should edit a saved search", function* () {
|
||||||
|
var search = yield createDataObject('search');
|
||||||
|
var promise = waitForWindow('chrome://zotero/content/searchDialog.xul', function (win) {
|
||||||
|
let searchBox = win.document.getElementById('search-box');
|
||||||
|
var c = searchBox.search.getCondition(
|
||||||
|
searchBox.search.addCondition("title", "contains", "foo")
|
||||||
|
);
|
||||||
|
searchBox.addCondition(c);
|
||||||
|
Zotero.debug("ACCEPTING");
|
||||||
|
win.document.documentElement.acceptDialog();
|
||||||
|
});
|
||||||
|
yield zp.editSelectedCollection();
|
||||||
|
yield promise;
|
||||||
|
var conditions = search.getConditions();
|
||||||
|
Zotero.debug(conditions);
|
||||||
|
assert.lengthOf(Object.keys(conditions), 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue
Block a user