diff --git a/chrome/content/zotero/tools/testTranslators/translatorTester.js b/chrome/content/zotero/tools/testTranslators/translatorTester.js index 876fc970f1..946b566dff 100644 --- a/chrome/content/zotero/tools/testTranslators/translatorTester.js +++ b/chrome/content/zotero/tools/testTranslators/translatorTester.js @@ -193,13 +193,15 @@ var Zotero_TranslatorTesters = new function() { * @param {String} type The type of tests to run (web, import, export, or search) * @param {Function} [debugCallback] A function to call to write debug output. If not present, * Zotero.debug will be used. + * @param {Object} [translatorProvider] Used by Scaffold to override Zotero.Translators */ -var Zotero_TranslatorTester = function(translator, type, debugCallback) { +var Zotero_TranslatorTester = function(translator, type, debugCallback, translatorProvider) { this.type = type; this.translator = translator; this.output = ""; this.isSupported = this.translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER; this.translator.runMode = Zotero.Translator.RUN_MODE_IN_BROWSER; + this.translatorProvider = translatorProvider; this.tests = []; this.pending = []; @@ -441,7 +443,9 @@ Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback var me = this; var translate = Zotero.Translate.newInstance(this.type); - + if (this.translatorProvider) { + translate.setTranslatorProvider(this.translatorProvider); + } if(this.type === "web") { translate.setDocument(doc); } else if(this.type === "import") { @@ -602,6 +606,9 @@ Zotero_TranslatorTester.prototype.newTest = function(doc, testReadyCallback) { var me = this; var translate = Zotero.Translate.newInstance(this.type); + if (this.translatorProvider) { + translate.setTranslatorProvider(this.translatorProvider); + } translate.setDocument(doc); translate.setTranslator(this.translator); translate.setHandler("debug", this._debug); diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js index 42d816fff8..3599f02373 100644 --- a/chrome/content/zotero/xpcom/file.js +++ b/chrome/content/zotero/xpcom/file.js @@ -583,13 +583,14 @@ Zotero.File = new function(){ /** * Run a generator with an OS.File.DirectoryIterator, closing the - * iterator when done + * iterator when done. Promises yielded by the generator are awaited. * * The DirectoryIterator is passed as the first parameter to the generator. * * Zotero.File.iterateDirectory(path, function* (iterator) { * while (true) { - * var entry = yield iterator.next(); + * let entry = yield iterator.next(); + * let contents = yield Zotero.File.getContentsAsync(entry.path); * [...] * } * }) diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js index e742df5484..5e543f6d5a 100644 --- a/chrome/content/zotero/xpcom/translation/translate.js +++ b/chrome/content/zotero/xpcom/translation/translate.js @@ -330,6 +330,7 @@ Zotero.Translate.Sandbox = { Zotero.debug("Translate: Creating translate instance of type "+type+" in sandbox"); var translation = Zotero.Translate.newInstance(type); translation._parentTranslator = translate; + translation.setTranslatorProvider(translate._translatorProvider); if(translation instanceof Zotero.Translate.Export && !(translation instanceof Zotero.Translate.Export)) { throw(new Error("Only export translators may call other export translators")); @@ -435,7 +436,9 @@ Zotero.Translate.Sandbox = { } var translator = translation.translator[0]; - translator = typeof translator === "object" ? translator : Zotero.Translators.get(translator); + translator = typeof translator === "object" + ? translator + : translation._translatorProvider.get(translator); // Zotero.Translators.get returns a value in the client and a promise in connectors // so we normalize the value to a promise here Zotero.Promise.resolve(translator) @@ -948,6 +951,7 @@ Zotero.Translate.Base.prototype = { this._handlers = []; this._currentState = null; this._translatorInfo = null; + this._translatorProvider = Zotero.Translators; this.document = null; this.location = null; }, @@ -1071,6 +1075,17 @@ Zotero.Translate.Base.prototype = { if(handlerIndex !== -1) this._handlers[type].splice(handlerIndex, 1); }, + /** + * Set custom translator provider, as returned by Zotero.Translators.makeTranslatorProvider() + * + * Used by Scaffold to substitute external translator files + * + * @param {Object} translatorProvider + */ + setTranslatorProvider: function (translatorProvider) { + this._translatorProvider = translatorProvider; + }, + /** * Indicates that a new async process is running */ @@ -1177,7 +1192,7 @@ Zotero.Translate.Base.prototype = { var t; for(var i=0, n=this.translator.length; i doc))[0]; + }); + + it("should set a custom version of Zotero.Translators", async function () { + // Create a dummy translator to be returned by the stub methods + var info = { + translatorID: "e6111720-1f6c-42b0-a487-99b9fa50b8a1", + label: "Test", + creator: "Creator", + target: "^http:\/\/127.0.0.1:23119\/test", + minVersion: "5.0", + maxVersion: "", + priority: 100, + translatorType: 4, + browserSupport: "gcsibv", + lastUpdated: "2019-07-10 05:50:39", + cacheCode: true + }; + info.code = JSON.stringify(info, null, '\t') + "\n\n" + + "function detectWeb(doc, url) {" + + "return 'journalArticle';" + + "}\n" + + "function doWeb(doc, url) {" + + "var item = new Zotero.Item('journalArticle');" + + "item.title = 'Test';" + + "item.complete();" + + "}\n"; + var translator = new Zotero.Translator(info); + + var translate = new Zotero.Translate.Web(); + var provider = Zotero.Translators.makeTranslatorProvider({ + get: function (translatorID) { + if (translatorID == info.translatorID) { + return translator; + } + return false; + }, + + getAllForType: async function (type) { + var translators = []; + if (type == 'web') { + translators.push(translator); + } + return translators; + } + }); + translate.setTranslatorProvider(provider); + translate.setDocument(doc); + var translators = await translate.getTranslators(); + translate.setTranslator(translators[0]); + var newItems = await translate.translate(); + assert.equal(newItems.length, 1); + + var item = newItems[0]; + assert.equal(item.getField('title'), 'Test'); + }); + + it("should set a custom version of Zotero.Translators in a child translator", async function () { + // Create dummy translators to be returned by the stub methods + var info1 = { + translatorID: "e6111720-1f6c-42b0-a487-99b9fa50b8a1", + label: "Test", + creator: "Creator", + target: "^http:\/\/127.0.0.1:23119\/test", + minVersion: "5.0", + maxVersion: "", + priority: 100, + translatorType: 4, + browserSupport: "gcsibv", + lastUpdated: "2019-07-10 05:50:39", + cacheCode: true + }; + info1.code = JSON.stringify(info1, null, '\t') + "\n\n" + + "function detectWeb(doc, url) {" + + "return 'journalArticle';" + + "}\n" + + "function doWeb(doc, url) {" + + "var translator = Zotero.loadTranslator('import');" + + "translator.setTranslator('86e58f50-4e2d-4ee8-8a20-bafa225381fa');" + + "translator.setString('foo\\n');" + + "translator.setHandler('itemDone', function(obj, item) {" + + "item.complete();" + + "});" + + "translator.translate();" + + "}\n"; + var translator1 = new Zotero.Translator(info1); + + var info2 = { + translatorID: "86e58f50-4e2d-4ee8-8a20-bafa225381fa", + label: "Child Test", + creator: "Creator", + target: "", + minVersion: "5.0", + maxVersion: "", + priority: 100, + translatorType: 3, + browserSupport: "gcsibv", + lastUpdated: "2019-07-19 06:22:21", + cacheCode: true + }; + info2.code = JSON.stringify(info2, null, '\t') + "\n\n" + + "function detectImport() {" + + "return true;" + + "}\n" + + "function doImport() {" + + "var item = new Zotero.Item('journalArticle');" + + "item.title = 'Test';" + + "item.complete();" + + "}\n"; + var translator2 = new Zotero.Translator(info2); + + var translate = new Zotero.Translate.Web(); + var provider = Zotero.Translators.makeTranslatorProvider({ + get: function (translatorID) { + switch (translatorID) { + case info1.translatorID: + return translator1; + + case info2.translatorID: + return translator2; + } + return false; + }, + + getAllForType: async function (type) { + var translators = []; + if (type == 'web') { + translators.push(translator1); + } + if (type == 'import') { + translators.push(translator2); + } + return translators; + } + }); + translate.setTranslatorProvider(provider); + translate.setDocument(doc); + var translators = await translate.getTranslators(); + translate.setTranslator(translators[0]); + var newItems = await translate.translate(); + assert.equal(newItems.length, 1); + + var item = newItems[0]; + assert.equal(item.getField('title'), 'Test'); + }); + }); + + describe("Translators", function () { it("should round-trip child attachment via BibTeX", function* () { var item = yield createDataObject('item');