diff --git a/chrome/content/zotero/overlay.js b/chrome/content/zotero/overlay.js index 166e866d6..1f946da9d 100644 --- a/chrome/content/zotero/overlay.js +++ b/chrome/content/zotero/overlay.js @@ -59,7 +59,6 @@ var ZoteroOverlay = new function() } ZoteroPane_Overlay = ZoteroPane; - ZoteroPane.init(); // Open Zotero app tab, if in Fx 4 and requested by pref showInPref = Components.classes["@mozilla.org/preferences-service;1"] @@ -106,6 +105,8 @@ var ZoteroOverlay = new function() Zotero.logError(e); } + ZoteroPane.init(); + // TODO: Add only when progress window is open document.getElementById('appcontent').addEventListener('mousemove', Zotero.ProgressWindowSet.updateTimers, false); diff --git a/chrome/content/zotero/xpcom/data/dataObjects.js b/chrome/content/zotero/xpcom/data/dataObjects.js index 57f587156..2c33be246 100644 --- a/chrome/content/zotero/xpcom/data/dataObjects.js +++ b/chrome/content/zotero/xpcom/data/dataObjects.js @@ -416,19 +416,23 @@ Zotero.DataObjects.prototype._loadDataType = Zotero.Promise.coroutine(function* Zotero.DataObjects.prototype.loadAll = Zotero.Promise.coroutine(function* (libraryID, ids) { var t = new Date(); - var libraryName = Zotero.Libraries.get(libraryID).name; + var library = Zotero.Libraries.get(libraryID) Zotero.debug("Loading " + (ids ? ids.length : "all") + " " + (ids && ids.length == 1 ? this._ZDO_object : this._ZDO_objects) - + " in " + libraryName); + + " in " + library.name); + + library.setDataLoading(this._ZDO_object); let dataTypes = this.ObjectClass.prototype._dataTypes; for (let i = 0; i < dataTypes.length; i++) { yield this._loadDataType(dataTypes[i], libraryID, ids); } - Zotero.debug(`Loaded all data in ${libraryName} in ${new Date() - t} ms`); + Zotero.debug(`Loaded all ${this._ZDO_objects} in ${library.name} in ${new Date() - t} ms`); + + library.setDataLoaded(this._ZDO_object); }); diff --git a/chrome/content/zotero/xpcom/data/library.js b/chrome/content/zotero/xpcom/data/library.js index 1f2cf7f3b..cf5662a34 100644 --- a/chrome/content/zotero/xpcom/data/library.js +++ b/chrome/content/zotero/xpcom/data/library.js @@ -31,6 +31,9 @@ Zotero.Library = function(params = {}) { this._changed = {}; + this._dataLoaded = {}; + this._dataLoadedDeferreds = {}; + this._hasCollections = null; this._hasSearches = null; this._storageDownloadNeeded = false; @@ -344,6 +347,45 @@ Zotero.Library.prototype.loadAllDataTypes = Zotero.Promise.coroutine(function* ( yield Zotero.Items.loadAll(this.libraryID); }); +// +// Methods to handle promises that are resolved when object data is loaded for the library +// +Zotero.Library.prototype.getDataLoaded = function (objectType) { + return this._dataLoaded[objectType] || null; +}; + +Zotero.Library.prototype.setDataLoading = function (objectType) { + if (this._dataLoadedDeferreds[objectType]) { + throw new Error("Items already loading for library " + this.libraryID); + } + this._dataLoadedDeferreds[objectType] = Zotero.Promise.defer(); +}; + +Zotero.Library.prototype.getDataLoadedPromise = function (objectType) { + return this._dataLoadedDeferreds[objectType] + ? this._dataLoadedDeferreds[objectType].promise : null; +}; + +Zotero.Library.prototype.setDataLoaded = function (objectType) { + this._dataLoaded[objectType] = true; + this._dataLoadedDeferreds[objectType].resolve(); +}; + +Zotero.Library.prototype.waitForDataLoad = Zotero.Promise.coroutine(function* (objectType) { + if (this.getDataLoaded(objectType)) return; + + let promise = this.getDataLoadedPromise(objectType); + // If items are already being loaded, wait for them + if (promise) { + yield promise; + } + // Otherwise load them now + else { + let objectsClass = Zotero.DataObjectUtilities.getObjectsClassForObjectType(objectType); + yield objectsClass.loadAll(this.libraryID); + } +}); + Zotero.Library.prototype.isChildObjectAllowed = function(type) { return this._childObjectTypes.indexOf(type) != -1; }; diff --git a/chrome/content/zotero/xpcom/sync/syncRunner.js b/chrome/content/zotero/xpcom/sync/syncRunner.js index 17f2ceead..8434f6885 100644 --- a/chrome/content/zotero/xpcom/sync/syncRunner.js +++ b/chrome/content/zotero/xpcom/sync/syncRunner.js @@ -174,6 +174,15 @@ Zotero.Sync.Runner_Module = function (options = {}) { keyInfo, options.libraries ? Array.from(options.libraries) : [] ); + + // If items not yet loaded for libraries we need, load them now + for (let libraryID of librariesToSync) { + let library = Zotero.Libraries.get(libraryID); + if (!library.getDataLoaded('item')) { + yield library.waitForDataLoad('item'); + } + } + // Sync data and files, and then repeat if necessary let attempt = 1; let nextLibraries = librariesToSync.concat(); @@ -283,6 +292,9 @@ Zotero.Sync.Runner_Module = function (options = {}) { }); + /** + * @return {Promise - IDs of libraries to sync + */ this.checkLibraries = Zotero.Promise.coroutine(function* (client, options, keyInfo, libraries = []) { var access = keyInfo.access; diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index a65b20662..f3362f1f5 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -630,11 +630,15 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); yield Zotero.Relations.init(); yield Zotero.Feeds.init(); - let libraryIDs = Zotero.Libraries.getAll().map(x => x.libraryID); - for (let libraryID of libraryIDs) { - let library = Zotero.Libraries.get(libraryID); - yield library.loadAllDataTypes(); - } + // Load all library data except for items + yield Zotero.Promise.each( + Zotero.Libraries.getAll(), + library => Zotero.Promise.coroutine(function* () { + yield Zotero.SyncedSettings.loadAll(library.libraryID); + yield Zotero.Collections.loadAll(library.libraryID); + yield Zotero.Searches.loadAll(library.libraryID); + })() + ); yield Zotero.QuickCopy.init(); @@ -2120,22 +2124,21 @@ Components.utils.import("resource://gre/modules/osfile.jsm"); /* * Clear entries that no longer exist from various tables */ - this.purgeDataObjects = Zotero.Promise.coroutine(function* (skipStoragePurge) { + this.purgeDataObjects = Zotero.Promise.coroutine(function* () { yield Zotero.DB.executeTransaction(function* () { return Zotero.Creators.purge(); }); yield Zotero.DB.executeTransaction(function* () { return Zotero.Tags.purge(); }); - // TEMP: Disabled until we have async DB (and maybe SQLite FTS) - //Zotero.Fulltext.purgeUnusedWords(); + Zotero.Fulltext.purgeUnusedWords(); yield Zotero.DB.executeTransaction(function* () { return Zotero.Items.purge(); }); // DEBUG: this might not need to be permanent - yield Zotero.DB.executeTransaction(function* () { - return Zotero.Relations.purge(); - }); + //yield Zotero.DB.executeTransaction(function* () { + // return Zotero.Relations.purge(); + //}); }); diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 82ba1f09a..cc7f66b43 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -1214,6 +1214,15 @@ var ZoteroPane = new function() ZoteroPane_Local.displayErrorMessage(); }; this.itemsView.addEventListener('load', this.setTagScope); + + // If item data not yet loaded for library, load it now. + // Other data types are loaded at startup + var library = Zotero.Libraries.get(collectionTreeRow.ref.libraryID); + if (!library.getDataLoaded('item')) { + Zotero.debug("Waiting for items to load for library " + library.libraryID); + yield library.waitForDataLoad('item'); + } + document.getElementById('zotero-items-tree').view = this.itemsView; // Add events to treecolpicker to update menu before showing/hiding @@ -1920,7 +1929,7 @@ var ZoteroPane = new function() ); if (result) { let deleted = yield Zotero.Items.emptyTrash(libraryID); - yield Zotero.purgeDataObjects(true); + yield Zotero.purgeDataObjects(); } }); diff --git a/test/content/support.js b/test/content/support.js index 1b76ae036..ee253ecc4 100644 --- a/test/content/support.js +++ b/test/content/support.js @@ -53,11 +53,6 @@ var loadZoteroPane = Zotero.Promise.coroutine(function* (win) { Zotero.Prefs.clear('lastViewedFolder'); win.ZoteroOverlay.toggleDisplay(true); - // Hack to wait for pane load to finish. This is the same hack - // we use in ZoteroPane.js, so either it's not good enough - // there or it should be good enough here. - yield Zotero.Promise.delay(52); - yield waitForItemsLoad(win, 0); return win;