diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js index 0f780ba19..000ef5edf 100644 --- a/chrome/content/zotero/xpcom/itemTreeView.js +++ b/chrome/content/zotero/xpcom/itemTreeView.js @@ -2532,8 +2532,6 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) { } // Get Quick Copy format for current URL -// TODO: Fix this -/** Currently broken var url = this._ownerDocument.defaultView.content && this._ownerDocument.defaultView.content.location ? this._ownerDocument.defaultView.content.location.href : null; var format = Zotero.QuickCopy.getFormatFromURL(url); @@ -2572,7 +2570,6 @@ Zotero.ItemTreeView.prototype.onDragStart = function (event) { Zotero.debug(e); Components.utils.reportError(e + " with '" + format.id + "'"); } -*/ }; diff --git a/chrome/content/zotero/xpcom/quickCopy.js b/chrome/content/zotero/xpcom/quickCopy.js index 307ba33a9..6862c2402 100644 --- a/chrome/content/zotero/xpcom/quickCopy.js +++ b/chrome/content/zotero/xpcom/quickCopy.js @@ -27,9 +27,18 @@ Zotero.QuickCopy = new function() { var _siteSettings; var _formattedNames; + var _initialized = false; this.init = Zotero.Promise.coroutine(function* () { yield this.loadSiteSettings(); + + // Load code for selected export translator ahead of time + // (in the background, because it requires translator initialization) + setTimeout(_loadOutputFormat, 5000); + if (!_initialized) { + Zotero.Prefs.registerObserver("export.quickCopy.setting", () => _loadOutputFormat()); + _initialized = true; + } }); @@ -405,6 +414,22 @@ Zotero.QuickCopy = new function() { }; + /** + * If an export translator is the selected output format, load its code (which must be done + * asynchronously) ahead of time, since drag-and-drop requires synchronous operation + */ + var _loadOutputFormat = Zotero.Promise.coroutine(function* () { + var format = Zotero.Prefs.get("export.quickCopy.setting"); + format = Zotero.QuickCopy.unserializeSetting(format); + if (format.mode == 'export') { + yield Zotero.Translators.init(); + let translator = Zotero.Translators.get(format.id); + translator.cacheCode = true; + yield translator.getCode(); + } + }); + + var _loadFormattedNames = Zotero.Promise.coroutine(function* () { var t = new Date; Zotero.debug("Loading formatted names for Quick Copy"); diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js index 97fd89d1a..ec4758fb8 100644 --- a/chrome/content/zotero/xpcom/translation/translate.js +++ b/chrome/content/zotero/xpcom/translation/translate.js @@ -1245,15 +1245,22 @@ Zotero.Translate.Base.prototype = { this.setHandler("done", doneHandler); this.setHandler("error", errorHandler); - if(typeof this.translator[0] === "object") { - // already have a translator object, so use it - this._loadTranslator(this.translator[0]).then(function() { me._translateTranslatorLoaded() }); - } else { - // need to get translator first - let translator = Zotero.Translators.get(this.translator[0]); - this.translator[0] = translator; - this._loadTranslator(translator).then(function() { me._translateTranslatorLoaded() }); + // need to get translator first + if (typeof this.translator[0] !== "object") { + this.translator[0] = Zotero.Translators.get(this.translator[0]); } + + var loadPromise = this._loadTranslator(this.translator[0]); + if (this.noWait) { + if (!loadPromise.isResolved()) { + return Zotero.Promise.reject(new Error("Load promise is not resolved in noWait mode")); + } + this._translateTranslatorLoaded(); + } + else { + loadPromise.then(() => this._translateTranslatorLoaded()); + } + return deferred.promise; }, @@ -1633,7 +1640,7 @@ Zotero.Translate.Base.prototype = { * @param {Zotero.Translator} translator * @return {Boolean} Whether the translator could be successfully loaded */ - "_loadTranslator":function(translator) { + "_loadTranslator": Zotero.Promise.method(function (translator) { var sandboxLocation = this._getSandboxLocation(); if(!this._sandboxLocation || sandboxLocation !== this._sandboxLocation) { this._sandboxLocation = sandboxLocation; @@ -1646,19 +1653,42 @@ Zotero.Translate.Base.prototype = { this._aborted = false; this.saveQueue = []; - var me = this; - return translator.getCode().then(function(code) { + var parse = function(code) { Zotero.debug("Translate: Parsing code for " + translator.label + " " + "(" + translator.translatorID + ", " + translator.lastUpdated + ")", 4); - me._sandboxManager.eval("var exports = {}, ZOTERO_TRANSLATOR_INFO = "+code, - ["detect"+me._entryFunctionSuffix, "do"+me._entryFunctionSuffix, "exports", - "ZOTERO_TRANSLATOR_INFO"], - (translator.file ? translator.file.path : translator.label)); - me._translatorInfo = me._sandboxManager.sandbox.ZOTERO_TRANSLATOR_INFO; - }).catch(function(e) { - me.complete(false, e); - }); - }, + this._sandboxManager.eval( + "var exports = {}, ZOTERO_TRANSLATOR_INFO = " + code, + [ + "detect" + this._entryFunctionSuffix, + "do" + this._entryFunctionSuffix, + "exports", + "ZOTERO_TRANSLATOR_INFO" + ], + (translator.file ? translator.file.path : translator.label) + ); + this._translatorInfo = this._sandboxManager.sandbox.ZOTERO_TRANSLATOR_INFO; + }.bind(this); + + if (this.noWait) { + try { + let codePromise = translator.getCode(); + if (!codePromise.isResolved()) { + throw new Error("Code promise is not resolved in noWait mode"); + } + parse(codePromise.value()); + } + catch (e) { + this.complete(false, e); + } + } + else { + return translator.getCode() + .then(parse) + .catch(function(e) { + this.complete(false, e); + }.bind(this)); + } + }), /** * Generates a sandbox for scraping/scraper detection diff --git a/test/tests/quickCopyTest.js b/test/tests/quickCopyTest.js index 44941b70b..62cd19e49 100644 --- a/test/tests/quickCopyTest.js +++ b/test/tests/quickCopyTest.js @@ -33,4 +33,28 @@ describe("Zotero.QuickCopy", function() { assert.deepEqual(Zotero.QuickCopy.getFormatFromURL('chrome://zotero/content/tab.xul'), quickCopyPref); }) }) + + describe("#getContentFromItems()", function () { + it("should generate BibTeX", function* () { + var item = yield createDataObject('item'); + var content = ""; + var worked = false; + + var format = 'export=9cb70025-a888-4a29-a210-93ec52da40d4'; // BibTeX + Zotero.Prefs.set('export.quickCopy.setting', format); + // The translator code is loaded automatically on pref change, but let's not wait for it + yield Zotero.QuickCopy.init(); + + Zotero.QuickCopy.getContentFromItems( + [item], + format, + (obj, w) => { + content = obj.string; + worked = w; + } + ); + assert.isTrue(worked); + assert.isTrue(content.trim().startsWith('@')); + }); + }); })