diff --git a/chrome/content/zotero/xpcom/fulltext.js b/chrome/content/zotero/xpcom/fulltext.js index 2757192650..46bde8a1b0 100644 --- a/chrome/content/zotero/xpcom/fulltext.js +++ b/chrome/content/zotero/xpcom/fulltext.js @@ -290,6 +290,7 @@ Zotero.Fulltext = Zotero.FullText = new function(){ Zotero.DB.query(sql, [itemID, {string:text}]); */ + Zotero.Notifier.queue('index', 'item', itemID); Zotero.Notifier.queue('refresh', 'item', itemID); }.bind(this)); diff --git a/chrome/content/zotero/xpcom/notifier.js b/chrome/content/zotero/xpcom/notifier.js index f6dcebd1e5..27c3d10868 100644 --- a/chrome/content/zotero/xpcom/notifier.js +++ b/chrome/content/zotero/xpcom/notifier.js @@ -93,7 +93,7 @@ Zotero.Notifier = new function(){ * Possible values: * * event: 'add', 'modify', 'delete', 'move' ('c', for changing parent), - * 'remove' (ci, it), 'refresh', 'redraw', 'trash', 'unreadCountUpdated' + * 'remove' (ci, it), 'refresh', 'redraw', 'trash', 'unreadCountUpdated', 'index' * type - 'collection', 'search', 'item', 'collection-item', 'item-tag', 'tag', * 'group', 'relation', 'feed', 'feedItem' * ids - single id or array of ids diff --git a/chrome/content/zotero/xpcom/sync/syncEventListeners.js b/chrome/content/zotero/xpcom/sync/syncEventListeners.js index 01d0ace97f..f7a18c5ff8 100644 --- a/chrome/content/zotero/xpcom/sync/syncEventListeners.js +++ b/chrome/content/zotero/xpcom/sync/syncEventListeners.js @@ -99,7 +99,8 @@ Zotero.Sync.EventListeners.ChangeListener = new function () { Zotero.Sync.EventListeners.AutoSyncListener = { - _editTimeout: 15, + _editTimeout: 3, + _noteEditTimeout: 15, _observerID: null, init: function () { @@ -114,13 +115,15 @@ Zotero.Sync.EventListeners.AutoSyncListener = { }, notify: function (event, type, ids, extraData) { - // TODO: skip others - if (event == 'refresh' || event == 'redraw') { - return; - } - - if (Zotero.Sync.Runner.syncInProgress) { - return; + switch (event) { + case 'add': + case 'modify': + case 'delete': + case 'index': + break; + + default: + return; } // Only trigger sync for certain types @@ -131,6 +134,8 @@ Zotero.Sync.EventListeners.AutoSyncListener = { // Determine affected libraries so only those can be synced let libraries = []; + var fileLibraries = new Set(); + var fullTextLibraries = new Set(); if (type == 'setting') { for (let id of ids) { @@ -163,11 +168,33 @@ Zotero.Sync.EventListeners.AutoSyncListener = { return; } + var noteEdit = false; + if (type == 'item' && (event == 'add' || event == 'modify' || event == 'index')) { + // Use a longer timeout for a single note edit, to avoid repeating syncing during typing + if (ids.length == 1 && (Zotero.Items.get(ids[0]) || {}).itemType == 'note') { + noteEdit = true; + } + else { + for (let id of ids) { + let item = Zotero.Items.get(id); + if (!item) continue; + if (item.isStoredFileAttachment()) { + fileLibraries.add(item.libraryID); + } + if (item.isFileAttachment()) { + fullTextLibraries.add(item.libraryID); + } + } + } + } + Zotero.Sync.Runner.setSyncTimeout( - this._editTimeout, + noteEdit ? this._noteEditTimeout : this._editTimeout, false, { - libraries: libraries.map(library => library.libraryID) + libraries: libraries.map(library => library.libraryID), + fileLibraries: [...fileLibraries], + fullTextLibraries: [...fullTextLibraries] } ); }, diff --git a/chrome/content/zotero/xpcom/sync/syncRunner.js b/chrome/content/zotero/xpcom/sync/syncRunner.js index 22fd05e5c1..80b5ccda0e 100644 --- a/chrome/content/zotero/xpcom/sync/syncRunner.js +++ b/chrome/content/zotero/xpcom/sync/syncRunner.js @@ -75,6 +75,7 @@ Zotero.Sync.Runner_Module = function (options = {}) { var _delayPromises = []; var _firstInSession = true; var _syncInProgress = false; + var _queuedSyncOptions = []; var _stopping = false; var _canceller; var _manualSyncRequired = false; // TODO: make public? @@ -238,6 +239,19 @@ Zotero.Sync.Runner_Module = function (options = {}) { options.libraries ? Array.from(options.libraries) : [] ); + // If file and full-text libraries are specified, limit to libraries we're already + // syncing + var fileLibrariesToSync = new Set( + options.fileLibraries + ? options.fileLibraries.filter(id => librariesToSync.includes(id)) + : librariesToSync + ); + var fullTextLibrariesToSync = new Set( + options.fullTextLibraries + ? options.fullTextLibraries.filter(id => librariesToSync.includes(id)) + : librariesToSync + ); + _stopCheck(); // If items not yet loaded for libraries we need, load them now @@ -268,8 +282,11 @@ Zotero.Sync.Runner_Module = function (options = {}) { _stopCheck(); - // Run file sync on all libraries that passed the last data sync - librariesToSync = yield _doFileSync(nextLibraries, engineOptions); + // Run file sync on all allowed libraries that passed the last data sync + librariesToSync = yield _doFileSync( + nextLibraries.filter(libraryID => fileLibrariesToSync.has(libraryID)), + engineOptions + ); if (librariesToSync.length) { attempt++; continue; @@ -277,8 +294,11 @@ Zotero.Sync.Runner_Module = function (options = {}) { _stopCheck(); - // Run full-text sync on all libraries that haven't failed a data sync - librariesToSync = yield _doFullTextSync([...successfulLibraries], engineOptions); + // Run full-text sync on all allowed libraries that haven't failed a data sync + librariesToSync = yield _doFullTextSync( + [...successfulLibraries].filter(libraryID => fullTextLibrariesToSync.has(libraryID)), + engineOptions + ); if (librariesToSync.length) { attempt++; continue; @@ -314,6 +334,12 @@ Zotero.Sync.Runner_Module = function (options = {}) { yield this._sync(options); return; } + // If an auto-sync was queued while a sync was ongoing, start again with its options + else if (_queuedSyncOptions.length) { + Zotero.debug("Restarting sync"); + yield this._sync(_queuedSyncOptions.shift()); + return; + } Zotero.debug("Done syncing"); Zotero.Notifier.trigger('finish', 'sync', librariesToSync || []); @@ -942,11 +968,13 @@ Zotero.Sync.Runner_Module = function (options = {}) { if (Zotero.locked) { Zotero.debug('Zotero is locked -- skipping auto-sync', 4); + _queuedSyncOptions.push(mergedOpts); return; } if (_syncInProgress) { Zotero.debug('Sync already in progress -- skipping auto-sync', 4); + _queuedSyncOptions.push(mergedOpts); return; } @@ -968,6 +996,7 @@ Zotero.Sync.Runner_Module = function (options = {}) { else { if (_syncInProgress) { Zotero.debug('Sync in progress -- not setting auto-sync timeout', 4); + _queuedSyncOptions.push(mergedOpts); return; } diff --git a/test/tests/syncEventListenersTest.js b/test/tests/syncEventListenersTest.js index 77c5c369bb..3a4de4488c 100644 --- a/test/tests/syncEventListenersTest.js +++ b/test/tests/syncEventListenersTest.js @@ -96,5 +96,23 @@ describe("Zotero.Sync.EventListeners", function () { mock.verify(); assert.sameMembers(expectation.getCall(0).args[2].libraries, [Zotero.Libraries.userLibraryID]); }); + + it("should auto-sync after attachment reindex", async function () { + Zotero.Prefs.set('sync.autoSync', false); + var attachment = await importFileAttachment('test.pdf'); + Zotero.Prefs.set('sync.autoSync', true); + + var mock = sinon.mock(Zotero.Sync.Runner); + var expectation = mock.expects("setSyncTimeout").once(); + + await Zotero.Fulltext.indexItems(attachment.id); + + await Zotero.Promise.delay(10); + mock.verify(); + assert.sameMembers( + expectation.getCall(0).args[2].fullTextLibraries, + [Zotero.Libraries.userLibraryID] + ); + }); }); });