Update zotero://select to use new URLs and wait for items list load

Closes #541
This commit is contained in:
Dan Stillman 2014-09-23 01:11:41 -04:00
parent c917d9e30e
commit e2d3cc3f0d
7 changed files with 288 additions and 159 deletions

View File

@ -36,7 +36,13 @@ Zotero.API = {
getResultsFromParams: Zotero.Promise.coroutine(function* (params) { getResultsFromParams: Zotero.Promise.coroutine(function* (params) {
if (!params.objectType) {
throw new Error("objectType not specified");
}
var results; var results;
if (params.objectType == 'item') {
switch (params.scopeObject) { switch (params.scopeObject) {
case 'collections': case 'collections':
if (params.scopeObjectKey) { if (params.scopeObjectKey) {
@ -82,25 +88,35 @@ Zotero.API = {
throw new Error("Invalid scope object '" + params.scopeObject + "'"); throw new Error("Invalid scope object '" + params.scopeObject + "'");
} }
if (params.itemKey) {
var s = new Zotero.Search; var s = new Zotero.Search;
if (params.libraryID !== undefined) {
yield s.addCondition('libraryID', 'is', params.libraryID); yield s.addCondition('libraryID', 'is', params.libraryID);
}
if (params.objectKey) {
yield s.addCondition('key', 'is', params.objectKey);
}
else if (params.objectID) {
Zotero.debug('adding ' + params.objectID);
yield s.addCondition('itemID', 'is', params.objectID);
}
if (params.itemKey) {
yield s.addCondition('blockStart'); yield s.addCondition('blockStart');
for (let i=0; i<params.itemKey.length; i++) { for (let i=0; i<params.itemKey.length; i++) {
let itemKey = params.itemKey[i]; let itemKey = params.itemKey[i];
yield s.addCondition('key', 'is', itemKey); yield s.addCondition('key', 'is', itemKey);
} }
yield s.addCondition('blockEnd'); yield s.addCondition('blockEnd');
var ids = yield s.search();
} }
else {
// Display all items // Display all top-level items
var s = new Zotero.Search(); /*if (params.onlyTopLevel) {
yield s.addCondition('libraryID', 'is', params.libraryID);
yield s.addCondition('noChildren', 'true'); yield s.addCondition('noChildren', 'true');
}*/
var ids = yield s.search(); var ids = yield s.search();
} }
}
if (results) { if (results) {
// Filter results by item key // Filter results by item key
@ -120,6 +136,10 @@ Zotero.API = {
} }
results = yield Zotero.Items.getAsync(ids); results = yield Zotero.Items.getAsync(ids);
} }
}
else {
throw new Error("Unsupported object type '" + params.objectType + "'");
}
return results; return results;
}), }),

View File

@ -36,10 +36,11 @@
*/ */
Zotero.CollectionTreeView = function() Zotero.CollectionTreeView = function()
{ {
Zotero.LibraryTreeView.apply(this);
this.itemToSelect = null; this.itemToSelect = null;
this.hideSources = []; this.hideSources = [];
this._treebox = null;
this._highlightedRows = {}; this._highlightedRows = {};
this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'trash', 'bucket'], 'collectionTreeView'); this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'trash', 'bucket'], 'collectionTreeView');
this._containerState = {}; this._containerState = {};
@ -57,6 +58,8 @@ Object.defineProperty(Zotero.CollectionTreeView.prototype, "selectedTreeRow", {
} }
}); });
/* /*
* Called by the tree itself * Called by the tree itself
*/ */
@ -93,6 +96,9 @@ Zotero.CollectionTreeView.prototype.setTree = Zotero.Promise.coroutine(function*
var row = yield this.getLastViewedRow(); var row = yield this.getLastViewedRow();
this.selection.select(row); this.selection.select(row);
this._treebox.ensureRowIsVisible(row); this._treebox.ensureRowIsVisible(row);
yield this._runListeners('load');
this._initialized = true;
} }
catch (e) { catch (e) {
Zotero.debug(e, 1); Zotero.debug(e, 1);

View File

@ -35,18 +35,16 @@
* Constructor for the ItemTreeView object * Constructor for the ItemTreeView object
*/ */
Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) { Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
Zotero.LibraryTreeView.apply(this);
this.wrappedJSObject = this; this.wrappedJSObject = this;
this.rowCount = 0; this.rowCount = 0;
this.collectionTreeRow = collectionTreeRow; this.collectionTreeRow = collectionTreeRow;
this._initialized = false;
this._skipKeypress = false; this._skipKeypress = false;
this._sourcesOnly = sourcesOnly; this._sourcesOnly = sourcesOnly;
this._callbacks = [];
this._treebox = null;
this._ownerDocument = null; this._ownerDocument = null;
this._needsSort = false; this._needsSort = false;
@ -62,17 +60,6 @@ Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
Zotero.ItemTreeView.prototype = Object.create(Zotero.LibraryTreeView.prototype); Zotero.ItemTreeView.prototype = Object.create(Zotero.LibraryTreeView.prototype);
Zotero.ItemTreeView.prototype.type = 'item'; Zotero.ItemTreeView.prototype.type = 'item';
Zotero.ItemTreeView.prototype.addCallback = function(callback) {
this._callbacks.push(callback);
}
Zotero.ItemTreeView.prototype._runCallbacks = Zotero.Promise.coroutine(function* () {
for each(var cb in this._callbacks) {
yield Zotero.Promise.resolve(cb());
}
});
/** /**
* Called by the tree itself * Called by the tree itself
@ -251,12 +238,12 @@ Zotero.ItemTreeView.prototype.setTree = Zotero.Promise.coroutine(function* (tree
yield this.sort(); yield this.sort();
// Only yield if there are callbacks; otherwise, we're almost done // Only yield if there are callbacks; otherwise, we're almost done
if(this._callbacks.length && this._waitAfter && Date.now() > this._waitAfter) yield Zotero.Promise.resolve(); if (this._listeners.load.length && this._waitAfter && Date.now() > this._waitAfter) yield Zotero.Promise.resolve();
yield this.expandMatchParents(); yield this.expandMatchParents();
//Zotero.debug('Running callbacks in itemTreeView.setTree()', 4); yield this._runListeners('load');
yield this._runCallbacks(); this._initialized = true;
if (this._ownerDocument.defaultView.ZoteroPane_Local) { if (this._ownerDocument.defaultView.ZoteroPane_Local) {
this._ownerDocument.defaultView.ZoteroPane_Local.clearItemsPaneMessage(); this._ownerDocument.defaultView.ZoteroPane_Local.clearItemsPaneMessage();
@ -1805,8 +1792,7 @@ Zotero.ItemTreeView.prototype.setFilter = Zotero.Promise.coroutine(function* (ty
//this._treebox.endUpdateBatch(); //this._treebox.endUpdateBatch();
this.selection.selectEventsSuppressed = false; this.selection.selectEventsSuppressed = false;
//Zotero.debug('Running callbacks in itemTreeView.setFilter()', 4); yield this._runListeners('load');
yield this._runCallbacks();
}); });

View File

@ -23,8 +23,35 @@
***** END LICENSE BLOCK ***** ***** END LICENSE BLOCK *****
*/ */
Zotero.LibraryTreeView = function () {}; Zotero.LibraryTreeView = function () {
this._initialized = false;
this._listeners = {
load: []
};
};
Zotero.LibraryTreeView.prototype = { Zotero.LibraryTreeView.prototype = {
addEventListener: function(event, listener) {
if (event == 'load') {
// If already initialized run now
if (this._initialized) {
listener();
}
else {
this._listeners[event].push(listener);
}
}
},
_runListeners: Zotero.Promise.coroutine(function* (event) {
var listener;
while (listener = this._listeners[event].shift()) {
yield Zotero.Promise.resolve(listener());
}
}),
/** /**
* Called while a drag is over the tree * Called while a drag is over the tree
*/ */

View File

@ -2189,6 +2189,18 @@ Zotero.SearchConditions = new function(){
noLoad: true noLoad: true
}, },
{
name: 'itemID',
operators: {
is: true,
isNot: true
},
table: 'items',
field: 'itemID',
special: true,
noLoad: true
},
{ {
name: 'annotation', name: 'annotation',
operators: { operators: {

View File

@ -32,6 +32,7 @@ var ZoteroPane = new function()
var _unserialized = false; var _unserialized = false;
this.collectionsView = false; this.collectionsView = false;
this.itemsView = false; this.itemsView = false;
this._listeners = {};
this.__defineGetter__('loaded', function () _loaded); this.__defineGetter__('loaded', function () _loaded);
//Privileged methods //Privileged methods
@ -1099,7 +1100,7 @@ var ZoteroPane = new function()
this.onCollectionSelected = Zotero.Promise.coroutine(function* () { this.onCollectionSelected = Zotero.Promise.coroutine(function* () {
var collectionTreeRow = this.getCollectionTreeRow(); var collectionTreeRow = this.getCollectionTreeRow();
if (this.itemsView.collectionTreeRow == collectionTreeRow) { if (this.itemsView && this.itemsView.collectionTreeRow == collectionTreeRow) {
Zotero.debug("Collection selection hasn't changed"); Zotero.debug("Collection selection hasn't changed");
return; return;
} }
@ -1167,7 +1168,14 @@ var ZoteroPane = new function()
this.itemsView.onError = function () { this.itemsView.onError = function () {
ZoteroPane_Local.displayErrorMessage(); ZoteroPane_Local.displayErrorMessage();
}; };
this.itemsView.addCallback(this.setTagScope); // If any queued load listeners, set them to run when the tree is ready
if (this._listeners.itemsLoaded) {
let listener;
while (listener = this._listeners.itemsLoaded.shift()) {
this.itemsView.addEventListener('load', listener);
}
}
this.itemsView.addEventListener('load', this.setTagScope);
document.getElementById('zotero-items-tree').view = this.itemsView; document.getElementById('zotero-items-tree').view = this.itemsView;
// Add events to treecolpicker to update menu before showing/hiding // Add events to treecolpicker to update menu before showing/hiding
@ -1953,34 +1961,77 @@ var ZoteroPane = new function()
return false; return false;
} }
if (!this.itemsView) { // Restore window if it's in the dock
Components.utils.reportError("Items view not set in ZoteroPane_Local.selectItem()"); if (window.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MINIMIZED) {
return false; window.restore();
} }
var currentLibraryID = this.getSelectedLibraryID(); if (!this.collectionsView) {
throw new Error("Collections view not loaded");
}
var self = this;
this.collectionsView.addEventListener('load', function () {
Zotero.spawn(function* () {
var currentLibraryID = self.getSelectedLibraryID();
// If in a different library // If in a different library
if (item.libraryID != currentLibraryID) { if (item.libraryID != currentLibraryID) {
Zotero.debug("Library ID differs; switching library"); Zotero.debug("Library ID differs; switching library");
yield this.collectionsView.selectLibrary(item.libraryID); yield self.collectionsView.selectLibrary(item.libraryID);
} }
// Force switch to library view // Force switch to library view
else if (!this.collectionsView.selectedTreeRow.isLibrary() && inLibrary) { else if (!self.collectionsView.selectedTreeRow.isLibrary() && inLibrary) {
Zotero.debug("Told to select in library; switching to library"); Zotero.debug("Told to select in library; switching to library");
yield this.collectionsView.selectLibrary(item.libraryID); yield self.collectionsView.selectLibrary(item.libraryID);
} }
var selected = yield this.itemsView.selectItem(itemID, expand); self.addEventListener('itemsLoaded', function () {
Zotero.spawn(function* () {
var selected = yield self.itemsView.selectItem(itemID, expand);
if (!selected) { if (!selected) {
Zotero.debug("Item was not selected; switching to library"); Zotero.debug("Item was not selected; switching to library");
yield this.collectionsView.selectLibrary(item.libraryID); yield self.collectionsView.selectLibrary(item.libraryID);
yield this.itemsView.selectItem(itemID, expand); yield self.itemsView.selectItem(itemID, expand);
} }
});
});
});
});
// open Zotero pane
this.show();
return true; return true;
}); });
this.addEventListener = function (event, listener) {
if (event == 'itemsLoaded') {
if (this.itemsView) {
this.itemsView.addEventListener('load', listener);
}
else {
if (!this._listeners.itemsLoaded) {
this._listeners.itemsLoaded = [];
}
this._listeners.itemsLoaded.push(listener);
}
}
};
this._runListeners = Zotero.Promise.coroutine(function* (event) {
if (!this._listeners[event]) {
return;
}
var listener;
while (listener = this._listeners[event].shift()) {
yield Zotero.Promise.resolve(listener());
}
});
this.getSelectedLibraryID = function () { this.getSelectedLibraryID = function () {
return this.collectionsView.getSelectedLibraryID(); return this.collectionsView.getSelectedLibraryID();
} }

View File

@ -110,6 +110,7 @@ function ZoteroProtocolHandler() {
} }
var params = { var params = {
objectType: 'item',
format: 'html', format: 'html',
sort: 'title' sort: 'title'
}; };
@ -793,47 +794,68 @@ function ZoteroProtocolHandler() {
var SelectExtension = { var SelectExtension = {
newChannel: function (uri) { newChannel: function (uri) {
return new AsyncChannel(uri, function* () { return new AsyncChannel(uri, function* () {
generateContent:try { var path = uri.path;
if (!path) {
return 'Invalid URL';
}
// Strip leading '/'
path = path.substr(1);
var mimeType, content = ''; var mimeType, content = '';
var [path, queryString] = uri.path.substr(1).split('?'); var params = {
var [type, id] = path.split('/'); objectType: 'item'
};
var router = new Zotero.Router(params);
// currently only able to select one item // Item within a collection or search
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] router.add('library/:scopeObject/:scopeObjectKey/items/:objectKey', function () {
.getService(Components.interfaces.nsIWindowMediator); params.libraryID = 0;
var win = wm.getMostRecentWindow("navigator:browser"); });
router.add('groups/:groupID/:scopeObject/:scopeObjectKey/items/:objectKey');
// restore window if it's in the dock // All items
if(win.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MINIMIZED) { router.add('library/items/:objectKey', function () {
win.restore(); params.libraryID = 0;
} });
router.add('groups/:groupID/items/:objectKey');
// open Zotero pane // Old-style URLs
win.ZoteroPane.show(); router.add('item/:id', function () {
var lkh = Zotero.Items.parseLibraryKeyHash(params.id);
if(!id) return;
var lkh = Zotero.Items.parseLibraryKeyHash(id);
if (lkh) { if (lkh) {
var item = Zotero.Items.getByLibraryAndKey(lkh.libraryID, lkh.key); params.libraryID = lkh.libraryID;
params.objectKey = lkh.key;
} }
else { else {
var item = Zotero.Items.get(id); params.objectID = params.id;
} }
if (!item) { delete params.id;
var msg = "Item " + id + " not found in zotero://select"; });
router.run(path);
try {
Zotero.API.parseParams(params);
var results = yield Zotero.API.getResultsFromParams(params);
}
catch (e) {
Zotero.debug(e, 1);
return e.toString();
}
if (!results.length) {
var msg = "Selected items not found";
Zotero.debug(msg, 2); Zotero.debug(msg, 2);
Components.utils.reportError(msg); Components.utils.reportError(msg);
return; return;
} }
win.ZoteroPane.selectItem(item.id); var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
} .getService(Components.interfaces.nsIWindowMediator);
catch (e){ var win = wm.getMostRecentWindow("navigator:browser");
Zotero.debug(e);
throw (e); // TODO: Currently only able to select one item
} yield win.ZoteroPane.selectItem(results[0].id);
}); });
} }
}; };
@ -1226,13 +1248,18 @@ AsyncChannel.prototype = {
}); });
return promise; return promise;
} }
else if (data === undefined) {
this.cancel(0x804b0002); // BINDING_ABORTED
}
else { else {
throw new Error("Invalid return type (" + typeof data + ") from generator passed to AsyncChannel"); throw new Error("Invalid return type (" + typeof data + ") from generator passed to AsyncChannel");
} }
}.bind(this)) }.bind(this))
.then(function () { .then(function () {
if (this._isPending) {
Zotero.debug("AsyncChannel request succeeded in " + (new Date - t) + " ms"); Zotero.debug("AsyncChannel request succeeded in " + (new Date - t) + " ms");
channel._isPending = false; channel._isPending = false;
}
}) })
.catch(function (e) { .catch(function (e) {
Zotero.debug(e, 1); Zotero.debug(e, 1);