Update zotero://select to use new URLs and wait for items list load
Closes #541
This commit is contained in:
parent
c917d9e30e
commit
e2d3cc3f0d
|
@ -36,7 +36,13 @@ Zotero.API = {
|
|||
|
||||
|
||||
getResultsFromParams: Zotero.Promise.coroutine(function* (params) {
|
||||
if (!params.objectType) {
|
||||
throw new Error("objectType not specified");
|
||||
}
|
||||
|
||||
var results;
|
||||
|
||||
if (params.objectType == 'item') {
|
||||
switch (params.scopeObject) {
|
||||
case 'collections':
|
||||
if (params.scopeObjectKey) {
|
||||
|
@ -82,25 +88,35 @@ Zotero.API = {
|
|||
throw new Error("Invalid scope object '" + params.scopeObject + "'");
|
||||
}
|
||||
|
||||
if (params.itemKey) {
|
||||
var s = new Zotero.Search;
|
||||
if (params.libraryID !== undefined) {
|
||||
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');
|
||||
for (let i=0; i<params.itemKey.length; i++) {
|
||||
let itemKey = params.itemKey[i];
|
||||
yield s.addCondition('key', 'is', itemKey);
|
||||
}
|
||||
yield s.addCondition('blockEnd');
|
||||
var ids = yield s.search();
|
||||
}
|
||||
else {
|
||||
// Display all items
|
||||
var s = new Zotero.Search();
|
||||
yield s.addCondition('libraryID', 'is', params.libraryID);
|
||||
|
||||
// Display all top-level items
|
||||
/*if (params.onlyTopLevel) {
|
||||
yield s.addCondition('noChildren', 'true');
|
||||
}*/
|
||||
|
||||
var ids = yield s.search();
|
||||
}
|
||||
}
|
||||
|
||||
if (results) {
|
||||
// Filter results by item key
|
||||
|
@ -120,6 +136,10 @@ Zotero.API = {
|
|||
}
|
||||
results = yield Zotero.Items.getAsync(ids);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error("Unsupported object type '" + params.objectType + "'");
|
||||
}
|
||||
|
||||
return results;
|
||||
}),
|
||||
|
|
|
@ -36,10 +36,11 @@
|
|||
*/
|
||||
Zotero.CollectionTreeView = function()
|
||||
{
|
||||
Zotero.LibraryTreeView.apply(this);
|
||||
|
||||
this.itemToSelect = null;
|
||||
this.hideSources = [];
|
||||
|
||||
this._treebox = null;
|
||||
this._highlightedRows = {};
|
||||
this._unregisterID = Zotero.Notifier.registerObserver(this, ['collection', 'search', 'share', 'group', 'trash', 'bucket'], 'collectionTreeView');
|
||||
this._containerState = {};
|
||||
|
@ -57,6 +58,8 @@ Object.defineProperty(Zotero.CollectionTreeView.prototype, "selectedTreeRow", {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Called by the tree itself
|
||||
*/
|
||||
|
@ -93,6 +96,9 @@ Zotero.CollectionTreeView.prototype.setTree = Zotero.Promise.coroutine(function*
|
|||
var row = yield this.getLastViewedRow();
|
||||
this.selection.select(row);
|
||||
this._treebox.ensureRowIsVisible(row);
|
||||
|
||||
yield this._runListeners('load');
|
||||
this._initialized = true;
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
|
|
|
@ -35,18 +35,16 @@
|
|||
* Constructor for the ItemTreeView object
|
||||
*/
|
||||
Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
|
||||
Zotero.LibraryTreeView.apply(this);
|
||||
|
||||
this.wrappedJSObject = this;
|
||||
this.rowCount = 0;
|
||||
this.collectionTreeRow = collectionTreeRow;
|
||||
|
||||
this._initialized = false;
|
||||
this._skipKeypress = false;
|
||||
|
||||
this._sourcesOnly = sourcesOnly;
|
||||
|
||||
this._callbacks = [];
|
||||
|
||||
this._treebox = null;
|
||||
this._ownerDocument = null;
|
||||
this._needsSort = false;
|
||||
|
||||
|
@ -62,17 +60,6 @@ Zotero.ItemTreeView = function (collectionTreeRow, sourcesOnly) {
|
|||
Zotero.ItemTreeView.prototype = Object.create(Zotero.LibraryTreeView.prototype);
|
||||
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
|
||||
|
@ -251,12 +238,12 @@ Zotero.ItemTreeView.prototype.setTree = Zotero.Promise.coroutine(function* (tree
|
|||
yield this.sort();
|
||||
|
||||
// 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();
|
||||
|
||||
//Zotero.debug('Running callbacks in itemTreeView.setTree()', 4);
|
||||
yield this._runCallbacks();
|
||||
yield this._runListeners('load');
|
||||
this._initialized = true;
|
||||
|
||||
if (this._ownerDocument.defaultView.ZoteroPane_Local) {
|
||||
this._ownerDocument.defaultView.ZoteroPane_Local.clearItemsPaneMessage();
|
||||
|
@ -1805,8 +1792,7 @@ Zotero.ItemTreeView.prototype.setFilter = Zotero.Promise.coroutine(function* (ty
|
|||
//this._treebox.endUpdateBatch();
|
||||
this.selection.selectEventsSuppressed = false;
|
||||
|
||||
//Zotero.debug('Running callbacks in itemTreeView.setFilter()', 4);
|
||||
yield this._runCallbacks();
|
||||
yield this._runListeners('load');
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -23,8 +23,35 @@
|
|||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.LibraryTreeView = function () {};
|
||||
Zotero.LibraryTreeView = function () {
|
||||
this._initialized = false;
|
||||
this._listeners = {
|
||||
load: []
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -2189,6 +2189,18 @@ Zotero.SearchConditions = new function(){
|
|||
noLoad: true
|
||||
},
|
||||
|
||||
{
|
||||
name: 'itemID',
|
||||
operators: {
|
||||
is: true,
|
||||
isNot: true
|
||||
},
|
||||
table: 'items',
|
||||
field: 'itemID',
|
||||
special: true,
|
||||
noLoad: true
|
||||
},
|
||||
|
||||
{
|
||||
name: 'annotation',
|
||||
operators: {
|
||||
|
|
|
@ -32,6 +32,7 @@ var ZoteroPane = new function()
|
|||
var _unserialized = false;
|
||||
this.collectionsView = false;
|
||||
this.itemsView = false;
|
||||
this._listeners = {};
|
||||
this.__defineGetter__('loaded', function () _loaded);
|
||||
|
||||
//Privileged methods
|
||||
|
@ -1099,7 +1100,7 @@ var ZoteroPane = new function()
|
|||
this.onCollectionSelected = Zotero.Promise.coroutine(function* () {
|
||||
var collectionTreeRow = this.getCollectionTreeRow();
|
||||
|
||||
if (this.itemsView.collectionTreeRow == collectionTreeRow) {
|
||||
if (this.itemsView && this.itemsView.collectionTreeRow == collectionTreeRow) {
|
||||
Zotero.debug("Collection selection hasn't changed");
|
||||
return;
|
||||
}
|
||||
|
@ -1167,7 +1168,14 @@ var ZoteroPane = new function()
|
|||
this.itemsView.onError = function () {
|
||||
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;
|
||||
|
||||
// Add events to treecolpicker to update menu before showing/hiding
|
||||
|
@ -1953,34 +1961,77 @@ var ZoteroPane = new function()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!this.itemsView) {
|
||||
Components.utils.reportError("Items view not set in ZoteroPane_Local.selectItem()");
|
||||
return false;
|
||||
// Restore window if it's in the dock
|
||||
if (window.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MINIMIZED) {
|
||||
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 (item.libraryID != currentLibraryID) {
|
||||
Zotero.debug("Library ID differs; switching library");
|
||||
yield this.collectionsView.selectLibrary(item.libraryID);
|
||||
yield self.collectionsView.selectLibrary(item.libraryID);
|
||||
}
|
||||
// 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");
|
||||
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) {
|
||||
Zotero.debug("Item was not selected; switching to library");
|
||||
yield this.collectionsView.selectLibrary(item.libraryID);
|
||||
yield this.itemsView.selectItem(itemID, expand);
|
||||
yield self.collectionsView.selectLibrary(item.libraryID);
|
||||
yield self.itemsView.selectItem(itemID, expand);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// open Zotero pane
|
||||
this.show();
|
||||
|
||||
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 () {
|
||||
return this.collectionsView.getSelectedLibraryID();
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ function ZoteroProtocolHandler() {
|
|||
}
|
||||
|
||||
var params = {
|
||||
objectType: 'item',
|
||||
format: 'html',
|
||||
sort: 'title'
|
||||
};
|
||||
|
@ -793,47 +794,68 @@ function ZoteroProtocolHandler() {
|
|||
var SelectExtension = {
|
||||
newChannel: function (uri) {
|
||||
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 [path, queryString] = uri.path.substr(1).split('?');
|
||||
var [type, id] = path.split('/');
|
||||
var params = {
|
||||
objectType: 'item'
|
||||
};
|
||||
var router = new Zotero.Router(params);
|
||||
|
||||
// currently only able to select one item
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
// Item within a collection or search
|
||||
router.add('library/:scopeObject/:scopeObjectKey/items/:objectKey', function () {
|
||||
params.libraryID = 0;
|
||||
});
|
||||
router.add('groups/:groupID/:scopeObject/:scopeObjectKey/items/:objectKey');
|
||||
|
||||
// restore window if it's in the dock
|
||||
if(win.windowState == Components.interfaces.nsIDOMChromeWindow.STATE_MINIMIZED) {
|
||||
win.restore();
|
||||
}
|
||||
// All items
|
||||
router.add('library/items/:objectKey', function () {
|
||||
params.libraryID = 0;
|
||||
});
|
||||
router.add('groups/:groupID/items/:objectKey');
|
||||
|
||||
// open Zotero pane
|
||||
win.ZoteroPane.show();
|
||||
|
||||
if(!id) return;
|
||||
|
||||
var lkh = Zotero.Items.parseLibraryKeyHash(id);
|
||||
// Old-style URLs
|
||||
router.add('item/:id', function () {
|
||||
var lkh = Zotero.Items.parseLibraryKeyHash(params.id);
|
||||
if (lkh) {
|
||||
var item = Zotero.Items.getByLibraryAndKey(lkh.libraryID, lkh.key);
|
||||
params.libraryID = lkh.libraryID;
|
||||
params.objectKey = lkh.key;
|
||||
}
|
||||
else {
|
||||
var item = Zotero.Items.get(id);
|
||||
params.objectID = params.id;
|
||||
}
|
||||
if (!item) {
|
||||
var msg = "Item " + id + " not found in zotero://select";
|
||||
delete params.id;
|
||||
});
|
||||
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);
|
||||
Components.utils.reportError(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
win.ZoteroPane.selectItem(item.id);
|
||||
}
|
||||
catch (e){
|
||||
Zotero.debug(e);
|
||||
throw (e);
|
||||
}
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
// TODO: Currently only able to select one item
|
||||
yield win.ZoteroPane.selectItem(results[0].id);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -1226,13 +1248,18 @@ AsyncChannel.prototype = {
|
|||
});
|
||||
return promise;
|
||||
}
|
||||
else if (data === undefined) {
|
||||
this.cancel(0x804b0002); // BINDING_ABORTED
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid return type (" + typeof data + ") from generator passed to AsyncChannel");
|
||||
}
|
||||
}.bind(this))
|
||||
.then(function () {
|
||||
if (this._isPending) {
|
||||
Zotero.debug("AsyncChannel request succeeded in " + (new Date - t) + " ms");
|
||||
channel._isPending = false;
|
||||
}
|
||||
})
|
||||
.catch(function (e) {
|
||||
Zotero.debug(e, 1);
|
||||
|
|
Loading…
Reference in New Issue
Block a user