Merge pull request #1293 from zotero/xhr-processDocuments
XMLHttpRequest() processDocuments
This commit is contained in:
commit
d073dec84d
13 changed files with 2174 additions and 637 deletions
7
.babelrc
7
.babelrc
|
@ -27,13 +27,6 @@
|
|||
"syntax-object-rest-spread",
|
||||
"transform-react-jsx",
|
||||
"transform-react-display-name",
|
||||
[
|
||||
"transform-async-to-module-method",
|
||||
{
|
||||
"module": "resource://zotero/bluebird.js",
|
||||
"method": "coroutine"
|
||||
}
|
||||
],
|
||||
[
|
||||
"transform-es2015-modules-commonjs",
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ var Zotero_TranslatorTesters = new function() {
|
|||
try {
|
||||
for(var i=0; i<translators.length; i++) {
|
||||
if (includeTranslators.length
|
||||
&& !includeTranslators.includes(translators[i].label)) continue;
|
||||
&& !includeTranslators.some(x => translators[i].label.includes(x))) continue;
|
||||
if (skipTranslators && skipTranslators[translators[i].translatorID]) continue;
|
||||
testers.push(new Zotero_TranslatorTester(translators[i], type));
|
||||
};
|
||||
|
@ -298,10 +298,18 @@ Zotero_TranslatorTester._sanitizeItem = function(item, testItem, keepValidFields
|
|||
|
||||
// remove fields to be ignored
|
||||
if(!keepValidFields && "accessDate" in item) delete item.accessDate;
|
||||
|
||||
//sort tags, if they're still there
|
||||
if(item.tags && typeof item.tags === "object" && "sort" in item.tags) {
|
||||
item.tags = Zotero.Utilities.arrayUnique(item.tags).sort();
|
||||
|
||||
// Sort tags
|
||||
if (item.tags && Array.isArray(item.tags)) {
|
||||
// Normalize tags -- necessary until tests are updated for 5.0
|
||||
if (testItem) {
|
||||
item.tags = Zotero.Translate.Base.prototype._cleanTags(item.tags);
|
||||
}
|
||||
item.tags.sort((a, b) => {
|
||||
if (a.tag < b.tag) return -1;
|
||||
if (b.tag < a.tag) return 1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
|
@ -391,54 +399,25 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
|
|||
|
||||
/**
|
||||
* Fetches the page for a given test and runs it
|
||||
*
|
||||
* This function is only applicable in Firefox; it is overridden in translator_global.js in Chrome
|
||||
* and Safari
|
||||
* @param {Object} test Test to execute
|
||||
* @param {Document} doc DOM document to test against
|
||||
* @param {Function} testDoneCallback A callback to be executed when test is complete
|
||||
* and Safari.
|
||||
*
|
||||
* @param {Object} test - Test to execute
|
||||
* @param {Function} testDoneCallback - A callback to be executed when test is complete
|
||||
*/
|
||||
Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneCallback) {
|
||||
var timer = Components.classes["@mozilla.org/timer;1"].
|
||||
createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback({"notify":function() {
|
||||
try {
|
||||
if (hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
}}, TEST_RUN_TIMEOUT, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
var me = this;
|
||||
var runTest = function(doc) {
|
||||
me.runTest(test, doc, function(obj, test, status, message) {
|
||||
try {
|
||||
timer.cancel();
|
||||
} catch(e) {};
|
||||
if(hiddenBrowser) Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
testDoneCallback(obj, test, status, message);
|
||||
});
|
||||
};
|
||||
var hiddenBrowser = Zotero.HTTP.processDocuments(test.url,
|
||||
function(doc) {
|
||||
if(test.defer) {
|
||||
me._debug(this, "TranslatorTesting: Waiting "
|
||||
+ (Zotero_TranslatorTester.DEFER_DELAY/1000)
|
||||
+ " second(s) for page content to settle"
|
||||
);
|
||||
Zotero.setTimeout(() => runTest(doc), Zotero_TranslatorTester.DEFER_DELAY);
|
||||
} else {
|
||||
runTest(doc);
|
||||
}
|
||||
},
|
||||
null,
|
||||
function(e) {
|
||||
testDoneCallback(this, test, "failed", "Translation failed to initialize: "+e);
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// No hidden browser returned from translation-server processDocuments()
|
||||
if (hiddenBrowser) {
|
||||
hiddenBrowser.docShell.allowMetaRedirects = true;
|
||||
}
|
||||
Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function (test, testDoneCallback) {
|
||||
Zotero.HTTP.processDocuments(
|
||||
test.url,
|
||||
(doc) => {
|
||||
this.runTest(test, doc, function (obj, test, status, message) {
|
||||
testDoneCallback(obj, test, status, message);
|
||||
});
|
||||
}
|
||||
)
|
||||
.catch(function (e) {
|
||||
testDoneCallback(this, test, "failed", "Translation failed to initialize: " + e);
|
||||
}.bind(this))
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -531,7 +510,9 @@ Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, transl
|
|||
}
|
||||
|
||||
translate.setTranslator(this.translator);
|
||||
translate.translate(false);
|
||||
translate.translate({
|
||||
libraryID: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -628,7 +609,9 @@ Zotero_TranslatorTester.prototype.newTest = function(doc, testReadyCallback) {
|
|||
});
|
||||
translate.setHandler("done", function(obj, returnValue) { me._createTest(obj, multipleMode, returnValue, testReadyCallback) });
|
||||
translate.capitalizeTitles = false;
|
||||
translate.translate(false);
|
||||
translate.translate({
|
||||
libraryID: false
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -265,7 +265,7 @@ Zotero.Attachments = new function(){
|
|||
// Save using a hidden browser
|
||||
var nativeHandlerImport = function () {
|
||||
return new Zotero.Promise(function (resolve, reject) {
|
||||
var browser = Zotero.HTTP.processDocuments(
|
||||
var browser = Zotero.HTTP.loadDocuments(
|
||||
url,
|
||||
Zotero.Promise.coroutine(function* () {
|
||||
let channel = browser.docShell.currentDocumentChannel;
|
||||
|
@ -591,7 +591,9 @@ Zotero.Attachments = new function(){
|
|||
}
|
||||
}
|
||||
|
||||
if (contentType === 'text/html' || contentType === 'application/xhtml+xml') {
|
||||
if ((contentType === 'text/html' || contentType === 'application/xhtml+xml')
|
||||
// Documents from XHR don't work here
|
||||
&& document instanceof Ci.nsIDOMDocument) {
|
||||
Zotero.debug('Saving document with saveDocument()');
|
||||
yield Zotero.Utilities.Internal.saveDocument(document, tmpFile);
|
||||
}
|
||||
|
|
|
@ -234,10 +234,12 @@ Zotero.FeedItem.prototype.translate = Zotero.Promise.coroutine(function* (librar
|
|||
}
|
||||
|
||||
// Load document
|
||||
let hiddenBrowser = Zotero.HTTP.processDocuments(
|
||||
this.getField('url'),
|
||||
item => deferred.resolve(item),
|
||||
()=>{}, error, true
|
||||
let hiddenBrowser = Zotero.HTTP.loadDocuments(
|
||||
this.getField('url'),
|
||||
doc => deferred.resolve(doc),
|
||||
() => {},
|
||||
error,
|
||||
true
|
||||
);
|
||||
let doc = yield deferred.promise;
|
||||
|
||||
|
|
|
@ -65,7 +65,10 @@ Zotero.HTTP = new function() {
|
|||
this[i] = options[i];
|
||||
}
|
||||
};
|
||||
this.SecurityException.prototype = Object.create(Zotero.Error.prototype);
|
||||
this.SecurityException.prototype = Object.create(
|
||||
// Zotero.Error not available in the connector
|
||||
Zotero.Error ? Zotero.Error.prototype : Error.prototype
|
||||
);
|
||||
|
||||
|
||||
this.promise = function () {
|
||||
|
@ -797,20 +800,81 @@ Zotero.HTTP = new function() {
|
|||
.getService(Components.interfaces.nsIIOService).offline;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load one or more documents using XMLHttpRequest
|
||||
*
|
||||
* This should stay in sync with the equivalent function in the connector
|
||||
*
|
||||
* @param {String|String[]} urls URL(s) of documents to load
|
||||
* @param {Function} processor - Callback to be executed for each document loaded; if function returns
|
||||
* a promise, it's waited for before continuing
|
||||
* @param {Zotero.CookieSandbox} [cookieSandbox] Cookie sandbox object
|
||||
* @return {Promise<Array>} - A promise for an array of results from the processor runs
|
||||
*/
|
||||
this.processDocuments = async function (urls, processor, cookieSandbox) {
|
||||
// Handle old signature: urls, processor, onDone, onError, dontDelete, cookieSandbox
|
||||
if (arguments.length > 3) {
|
||||
Zotero.debug("Zotero.HTTP.processDocuments() now takes only 3 arguments -- update your code");
|
||||
var onDone = arguments[2];
|
||||
var onError = arguments[3];
|
||||
var cookieSandbox = arguments[5];
|
||||
}
|
||||
|
||||
if (typeof urls == "string") urls = [urls];
|
||||
var funcs = urls.map(url => () => {
|
||||
return Zotero.HTTP.request(
|
||||
"GET",
|
||||
url,
|
||||
{
|
||||
responseType: 'document'
|
||||
}
|
||||
)
|
||||
.then((xhr) => {
|
||||
var doc = this.wrapDocument(xhr.response, url);
|
||||
return processor(doc, url);
|
||||
});
|
||||
});
|
||||
|
||||
// Run processes serially
|
||||
// TODO: Add some concurrency?
|
||||
var f;
|
||||
var results = [];
|
||||
while (f = funcs.shift()) {
|
||||
try {
|
||||
results.push(await f());
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load one or more documents in a hidden browser
|
||||
*
|
||||
* @param {String|String[]} urls URL(s) of documents to load
|
||||
* @param {Function} processor - Callback to be executed for each document loaded; if function returns
|
||||
* a promise, it's waited for before continuing
|
||||
* @param {Function} done Callback to be executed after all documents have been loaded
|
||||
* @param {Function} exception Callback to be executed if an exception occurs
|
||||
* @param {Function} onDone - Callback to be executed after all documents have been loaded
|
||||
* @param {Function} onError - Callback to be executed if an error occurs
|
||||
* @param {Boolean} dontDelete Don't delete the hidden browser upon completion; calling function
|
||||
* must call deleteHiddenBrowser itself.
|
||||
* @param {Zotero.CookieSandbox} [cookieSandbox] Cookie sandbox object
|
||||
* @return {browser} Hidden browser used for loading
|
||||
*/
|
||||
this.processDocuments = function(urls, processor, done, exception, dontDelete, cookieSandbox) {
|
||||
this.loadDocuments = function (urls, processor, onDone, onError, dontDelete, cookieSandbox) {
|
||||
// (Approximately) how many seconds to wait if the document is left in the loading state and
|
||||
// pageshow is called before we call pageshow with an incomplete document
|
||||
const LOADING_STATE_TIMEOUT = 120;
|
||||
|
@ -827,11 +891,11 @@ Zotero.HTTP = new function() {
|
|||
firedLoadEvent = 0;
|
||||
currentURL++;
|
||||
try {
|
||||
Zotero.debug("Zotero.HTTP.processDocuments: Loading "+url);
|
||||
Zotero.debug("Zotero.HTTP.loadDocuments: Loading " + url);
|
||||
hiddenBrowser.loadURI(url);
|
||||
} catch(e) {
|
||||
if(exception) {
|
||||
exception(e);
|
||||
if (onError) {
|
||||
onError(e);
|
||||
return;
|
||||
} else {
|
||||
if(!dontDelete) Zotero.Browser.deleteHiddenBrowser(hiddenBrowsers);
|
||||
|
@ -840,7 +904,7 @@ Zotero.HTTP = new function() {
|
|||
}
|
||||
} else {
|
||||
if(!dontDelete) Zotero.Browser.deleteHiddenBrowser(hiddenBrowsers);
|
||||
if(done) done();
|
||||
if (onDone) onDone();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -861,7 +925,7 @@ Zotero.HTTP = new function() {
|
|||
return;
|
||||
}
|
||||
|
||||
Zotero.debug("Zotero.HTTP.processDocuments: "+url+" loaded");
|
||||
Zotero.debug("Zotero.HTTP.loadDocuments: " + url + " loaded");
|
||||
hiddenBrowser.removeEventListener("pageshow", onLoad, true);
|
||||
hiddenBrowser.zotero_loaded = true;
|
||||
|
||||
|
@ -878,8 +942,8 @@ Zotero.HTTP = new function() {
|
|||
if (maybePromise && maybePromise.then) {
|
||||
maybePromise.then(() => doLoad())
|
||||
.catch(e => {
|
||||
if (exception) {
|
||||
exception(e);
|
||||
if (onError) {
|
||||
onError(e);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
|
@ -890,8 +954,8 @@ Zotero.HTTP = new function() {
|
|||
|
||||
try {
|
||||
if (error) {
|
||||
if (exception) {
|
||||
exception(error);
|
||||
if (onError) {
|
||||
onError(error);
|
||||
}
|
||||
else {
|
||||
throw error;
|
||||
|
|
|
@ -505,7 +505,7 @@ Zotero.Server.Connector.SaveSnapshot.prototype = {
|
|||
}
|
||||
else {
|
||||
let deferred = Zotero.Promise.defer();
|
||||
Zotero.HTTP.processDocuments(
|
||||
Zotero.HTTP.loadDocuments(
|
||||
["zotero://connector/" + encodeURIComponent(data.url)],
|
||||
Zotero.Promise.coroutine(function* (doc) {
|
||||
delete Zotero.Server.Connector.Data[data.url];
|
||||
|
|
|
@ -86,7 +86,7 @@ Zotero.Translate.Sandbox = {
|
|||
&& translate.translator[0].configOptions
|
||||
&& translate.translator[0].configOptions.async;
|
||||
|
||||
var run = function (resolve) {
|
||||
var run = async function (async) {
|
||||
Zotero.debug("Translate: Saving item");
|
||||
|
||||
// warn if itemDone called after translation completed
|
||||
|
@ -152,7 +152,7 @@ Zotero.Translate.Sandbox = {
|
|||
if(translate._libraryID === false || translate._parentTranslator) {
|
||||
translate.newItems.push(item);
|
||||
if(translate._parentTranslator && Zotero.isFx && !Zotero.isBookmarklet) {
|
||||
// Copy object so it is accessible to child translator
|
||||
// Copy object so it is accessible to parent translator
|
||||
item = translate._sandboxManager.copyObject(item);
|
||||
item.complete = oldItem.complete;
|
||||
}
|
||||
|
@ -216,12 +216,9 @@ Zotero.Translate.Sandbox = {
|
|||
|
||||
// For synchronous import (when Promise isn't available in the sandbox or the do*
|
||||
// function doesn't use it) and web translators, queue saves
|
||||
if (!resolve || !asyncTranslator) {
|
||||
if (!async || !asyncTranslator) {
|
||||
Zotero.debug("Translate: Saving via queue");
|
||||
translate.saveQueue.push(item);
|
||||
if (resolve) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
// For async import, save items immediately
|
||||
else {
|
||||
|
@ -240,11 +237,9 @@ Zotero.Translate.Sandbox = {
|
|||
|
||||
return new translate._sandboxManager.sandbox.Promise(function (resolve, reject) {
|
||||
try {
|
||||
let maybePromise = run(resolve);
|
||||
if (maybePromise) {
|
||||
maybePromise
|
||||
.then(resolve)
|
||||
.catch(function (e) {
|
||||
run(true).then(
|
||||
resolve,
|
||||
function (e) {
|
||||
// Fix wrapping error from sandbox when error is thrown from _saveItems()
|
||||
if (Zotero.isFx) {
|
||||
reject(translate._sandboxManager.copyObject(e));
|
||||
|
@ -252,8 +247,8 @@ Zotero.Translate.Sandbox = {
|
|||
else {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (e) {
|
||||
reject(e);
|
||||
|
@ -1106,7 +1101,9 @@ Zotero.Translate.Base.prototype = {
|
|||
|
||||
var handlers = this._handlers[type].slice();
|
||||
for(var i=0, n=handlers.length; i<n; i++) {
|
||||
Zotero.debug("Translate: Running handler "+i+" for "+type, 5);
|
||||
if (type != 'debug') {
|
||||
Zotero.debug(`Translate: Running handler ${i} for ${type}`, 5);
|
||||
}
|
||||
try {
|
||||
returnValue = handlers[i].apply(null, args);
|
||||
} catch(e) {
|
||||
|
|
|
@ -191,13 +191,22 @@ Zotero.Utilities.Translate.prototype.loadDocument = function(url, succeeded, fai
|
|||
}
|
||||
|
||||
/**
|
||||
* Already documented in Zotero.HTTP
|
||||
* Already documented in Zotero.HTTP, except this optionally takes noCompleteOnError, which prevents
|
||||
* the translation process from being cancelled automatically on error, as it is normally. The promise
|
||||
* is still rejected on error for handling by the calling function.
|
||||
* @ignore
|
||||
*/
|
||||
Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor, done, exception) {
|
||||
Zotero.Utilities.Translate.prototype.processDocuments = async function (urls, processor, noCompleteOnError) {
|
||||
// Handle old signature: urls, processor, onDone, onError
|
||||
if (arguments.length > 3 || typeof arguments[2] == 'function') {
|
||||
Zotero.debug("ZU.processDocuments() now takes only 3 arguments -- update your code");
|
||||
var onDone = arguments[2];
|
||||
var onError = arguments[3];
|
||||
}
|
||||
|
||||
var translate = this._translate;
|
||||
|
||||
if(typeof(urls) == "string") {
|
||||
if (typeof urls == "string") {
|
||||
urls = [translate.resolveURL(urls)];
|
||||
} else {
|
||||
for(var i in urls) {
|
||||
|
@ -205,109 +214,89 @@ Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor
|
|||
}
|
||||
}
|
||||
|
||||
// Unless the translator has proposed some way to handle an error, handle it
|
||||
// by throwing a "scraping error" message
|
||||
if(exception) {
|
||||
var myException = function(e) {
|
||||
var browserDeleted;
|
||||
try {
|
||||
exception(e);
|
||||
} catch(e) {
|
||||
if(hiddenBrowser) {
|
||||
try {
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
}
|
||||
browserDeleted = true;
|
||||
translate.complete(false, e);
|
||||
}
|
||||
|
||||
if(!browserDeleted) {
|
||||
try {
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
}
|
||||
var processDoc = function (doc) {
|
||||
if (Zotero.isFx) {
|
||||
let newLoc = doc.location;
|
||||
let url = Services.io.newURI(newLoc.href, null, null);
|
||||
return processor(
|
||||
// Rewrap document for the sandbox
|
||||
translate._sandboxManager.wrap(
|
||||
Zotero.Translate.DOMWrapper.unwrap(doc),
|
||||
null,
|
||||
// Duplicate overrides from Zotero.HTTP.wrapDocument()
|
||||
{
|
||||
documentURI: newLoc.spec,
|
||||
URL: newLoc.spec,
|
||||
location: new Zotero.HTTP.Location(url),
|
||||
defaultView: new Zotero.HTTP.Window(url)
|
||||
}
|
||||
),
|
||||
newLoc.href
|
||||
);
|
||||
}
|
||||
} else {
|
||||
var myException = function(e) {
|
||||
if(hiddenBrowser) {
|
||||
try {
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
}
|
||||
translate.complete(false, e);
|
||||
}
|
||||
}
|
||||
|
||||
return processor(doc, doc.location.href);
|
||||
};
|
||||
|
||||
if(Zotero.isFx) {
|
||||
if(typeof translate._sandboxLocation === "object") {
|
||||
var protocol = translate._sandboxLocation.location.protocol,
|
||||
host = translate._sandboxLocation.location.host;
|
||||
} else {
|
||||
var url = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService)
|
||||
.newURI(translate._sandboxLocation, null, null),
|
||||
protocol = url.scheme+":",
|
||||
host = url.host;
|
||||
}
|
||||
}
|
||||
|
||||
for(var i=0; i<urls.length; i++) {
|
||||
var funcs = [];
|
||||
// If current URL passed, use loaded document instead of reloading
|
||||
for (var i = 0; i < urls.length; i++) {
|
||||
if(translate.document && translate.document.location
|
||||
&& translate.document.location.toString() === urls[i]) {
|
||||
// Document is attempting to reload itself
|
||||
Zotero.debug("Translate: Attempted to load the current document using processDocuments; using loaded document instead");
|
||||
// This fixes document permissions issues in translation-server when translators call
|
||||
// processDocuments() on the original URL (e.g., AOSIC)
|
||||
// DEBUG: Why is this necessary? (see below also)
|
||||
if (Zotero.isServer) {
|
||||
processor(
|
||||
translate._sandboxManager.wrap(
|
||||
Zotero.Translate.DOMWrapper.unwrap(
|
||||
this._translate.document
|
||||
)
|
||||
),
|
||||
urls[i]
|
||||
);
|
||||
}
|
||||
else {
|
||||
processor(this._translate.document, urls[i]);
|
||||
}
|
||||
funcs.push(() => processDoc(this._translate.document, urls[i]));
|
||||
urls.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
translate.incrementAsyncProcesses("Zotero.Utilities.Translate#processDocuments");
|
||||
var hiddenBrowser = Zotero.HTTP.processDocuments(urls, function (doc, url) {
|
||||
if(!processor) return;
|
||||
|
||||
var newLoc = doc.location;
|
||||
if((Zotero.isFx && !Zotero.isBookmarklet && (protocol != newLoc.protocol || host != newLoc.host))
|
||||
// This fixes document permissions issues in translation-server when translators call
|
||||
// processDocuments() on same-domain URLs (e.g., some of the Code4Lib tests).
|
||||
// DEBUG: Is there a better fix for this?
|
||||
|| Zotero.isServer) {
|
||||
// Cross-site; need to wrap
|
||||
processor(translate._sandboxManager.wrap(doc), url);
|
||||
} else {
|
||||
// Not cross-site; no need to wrap
|
||||
processor(doc, url);
|
||||
}
|
||||
},
|
||||
function() {
|
||||
if(done) done();
|
||||
var handler = function() {
|
||||
if(hiddenBrowser) {
|
||||
try {
|
||||
Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
|
||||
} catch(e) {}
|
||||
|
||||
if (urls.length) {
|
||||
funcs.push(
|
||||
() => Zotero.HTTP.processDocuments(
|
||||
urls,
|
||||
function (doc) {
|
||||
if (!processor) return;
|
||||
return processDoc(doc);
|
||||
},
|
||||
translate.cookieSandbox
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
var f;
|
||||
while (f = funcs.shift()) {
|
||||
try {
|
||||
let maybePromise = f();
|
||||
// The processor may or may not return a promise
|
||||
if (maybePromise) {
|
||||
await maybePromise;
|
||||
}
|
||||
translate.removeHandler("done", handler);
|
||||
};
|
||||
translate.setHandler("done", handler);
|
||||
translate.decrementAsyncProcesses("Zotero.Utilities.Translate#processDocuments");
|
||||
}, myException, true, translate.cookieSandbox);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
try {
|
||||
onError(e);
|
||||
}
|
||||
catch (e) {
|
||||
translate.complete(false, e);
|
||||
}
|
||||
}
|
||||
// Unless instructed otherwise, end the translation on error
|
||||
else if (!noCompleteOnError) {
|
||||
translate.complete(false, e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
if (onDone) {
|
||||
onDone();
|
||||
}
|
||||
|
||||
translate.decrementAsyncProcesses("Zotero.Utilities.Translate#processDocuments");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3885,18 +3885,17 @@ var ZoteroPane = new function()
|
|||
var deferred = Zotero.Promise.defer();
|
||||
|
||||
var processor = function (doc) {
|
||||
ZoteroPane_Local.addItemFromDocument(doc, itemType, saveSnapshot, row)
|
||||
return ZoteroPane_Local.addItemFromDocument(doc, itemType, saveSnapshot, row)
|
||||
.then(function () {
|
||||
deferred.resolve()
|
||||
})
|
||||
});
|
||||
};
|
||||
// TODO: processDocuments should wait for the processor promise to be resolved
|
||||
var done = function () {}
|
||||
var exception = function (e) {
|
||||
Zotero.debug(e, 1);
|
||||
deferred.reject(e);
|
||||
}
|
||||
Zotero.HTTP.processDocuments([url], processor, done, exception);
|
||||
Zotero.HTTP.loadDocuments([url], processor, done, exception);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
2162
package-lock.json
generated
2162
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -30,7 +30,6 @@
|
|||
"babel-plugin-syntax-flow": "^6.13.0",
|
||||
"babel-plugin-syntax-jsx": "^6.13.0",
|
||||
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
|
||||
"babel-plugin-transform-async-to-module-method": "^6.16.0",
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
|
||||
"babel-preset-react": "^6.16.0",
|
||||
"browserify": "^14.3.0",
|
||||
|
|
76
test/tests/httpTest.js
Normal file
76
test/tests/httpTest.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
describe("Zotero.HTTP", function () {
|
||||
var httpd;
|
||||
var port = 16213;
|
||||
|
||||
before(function* () {
|
||||
Components.utils.import("resource://zotero-unit/httpd.js");
|
||||
|
||||
httpd = new HttpServer();
|
||||
httpd.start(port);
|
||||
httpd.registerPathHandler(
|
||||
'/test.html',
|
||||
{
|
||||
handle: function (request, response) {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write("<html><body><p>Test</p><p>Test 2</p></body></html>");
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
after(function* () {
|
||||
var defer = new Zotero.Promise.defer();
|
||||
httpd.stop(() => defer.resolve());
|
||||
yield defer.promise;
|
||||
});
|
||||
|
||||
describe("#processDocuments()", function () {
|
||||
it("should provide a document object", function* () {
|
||||
var called = false;
|
||||
var url = `http://127.0.0.1:${port}/test.html`;
|
||||
yield Zotero.HTTP.processDocuments(
|
||||
url,
|
||||
function (doc) {
|
||||
assert.equal(doc.location.href, url);
|
||||
assert.equal(doc.querySelector('p').textContent, 'Test');
|
||||
var p = doc.evaluate('//p', doc, null, XPathResult.ANY_TYPE, null).iterateNext();
|
||||
assert.equal(p.textContent, 'Test');
|
||||
called = true;
|
||||
}
|
||||
);
|
||||
assert.isTrue(called);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#loadDocuments()", function () {
|
||||
var win;
|
||||
|
||||
before(function* () {
|
||||
// TEMP: createHiddenBrowser currently needs a parent window
|
||||
win = yield loadBrowserWindow();
|
||||
});
|
||||
|
||||
after(function* () {
|
||||
win.close();
|
||||
});
|
||||
|
||||
it("should provide a document object", function* () {
|
||||
var called = false;
|
||||
var url = `http://127.0.0.1:${port}/test.html`;
|
||||
yield new Zotero.Promise((resolve) => {
|
||||
Zotero.HTTP.loadDocuments(
|
||||
url,
|
||||
function (doc) {
|
||||
assert.equal(doc.location.href, url);
|
||||
assert.equal(doc.querySelector('p').textContent, 'Test');
|
||||
var p = doc.evaluate('//p', doc, null, XPathResult.ANY_TYPE, null).iterateNext();
|
||||
assert.equal(p.textContent, 'Test');
|
||||
called = true;
|
||||
},
|
||||
resolve
|
||||
);
|
||||
});
|
||||
assert.isTrue(called);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -486,11 +486,15 @@ describe("Zotero.Translate", function() {
|
|||
checkTestTags(pdf, true);
|
||||
});
|
||||
|
||||
it('web translators should save attachment from document', function* () {
|
||||
it('web translators should save attachment from browser document', function* () {
|
||||
let deferred = Zotero.Promise.defer();
|
||||
let browser = Zotero.HTTP.processDocuments("http://127.0.0.1:23119/test/translate/test.html",
|
||||
function (doc) { deferred.resolve(doc) }, undefined,
|
||||
undefined, true);
|
||||
let browser = Zotero.HTTP.loadDocuments(
|
||||
"http://127.0.0.1:23119/test/translate/test.html",
|
||||
doc => deferred.resolve(doc),
|
||||
undefined,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
let doc = yield deferred.promise;
|
||||
|
||||
let translate = new Zotero.Translate.Web();
|
||||
|
@ -510,7 +514,7 @@ describe("Zotero.Translate", function() {
|
|||
'}'));
|
||||
let newItems = yield translate.translate();
|
||||
assert.equal(newItems.length, 1);
|
||||
let containedAttachments = yield Zotero.Items.getAsync(newItems[0].getAttachments());
|
||||
let containedAttachments = Zotero.Items.get(newItems[0].getAttachments());
|
||||
assert.equal(containedAttachments.length, 1);
|
||||
|
||||
let snapshot = containedAttachments[0];
|
||||
|
@ -522,6 +526,40 @@ describe("Zotero.Translate", function() {
|
|||
|
||||
Zotero.Browser.deleteHiddenBrowser(browser);
|
||||
});
|
||||
|
||||
it('web translators should save attachment from non-browser document', function* () {
|
||||
return Zotero.HTTP.processDocuments(
|
||||
"http://127.0.0.1:23119/test/translate/test.html",
|
||||
async function (doc) {
|
||||
let translate = new Zotero.Translate.Web();
|
||||
translate.setDocument(doc);
|
||||
translate.setTranslator(buildDummyTranslator(4,
|
||||
'function detectWeb() {}\n'+
|
||||
'function doWeb(doc) {\n'+
|
||||
' var item = new Zotero.Item("book");\n'+
|
||||
' item.title = "Container Item";\n'+
|
||||
' item.attachments = [{\n'+
|
||||
' "document":doc,\n'+
|
||||
' "title":"Snapshot from Document",\n'+
|
||||
' "note":"attachment note",\n'+
|
||||
' "tags":'+JSON.stringify(TEST_TAGS)+'\n'+
|
||||
' }];\n'+
|
||||
' item.complete();\n'+
|
||||
'}'));
|
||||
let newItems = await translate.translate();
|
||||
assert.equal(newItems.length, 1);
|
||||
let containedAttachments = Zotero.Items.get(newItems[0].getAttachments());
|
||||
assert.equal(containedAttachments.length, 1);
|
||||
|
||||
let snapshot = containedAttachments[0];
|
||||
assert.equal(snapshot.getField("url"), "http://127.0.0.1:23119/test/translate/test.html");
|
||||
assert.equal(snapshot.getNote(), "attachment note");
|
||||
assert.equal(snapshot.attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_URL);
|
||||
assert.equal(snapshot.attachmentContentType, "text/html");
|
||||
checkTestTags(snapshot, true);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('web translators should ignore attachments that return error codes', function* () {
|
||||
this.timeout(60000);
|
||||
|
@ -629,6 +667,117 @@ describe("Zotero.Translate", function() {
|
|||
});
|
||||
|
||||
|
||||
describe("#processDocuments()", function () {
|
||||
var url = "http://127.0.0.1:23119/test/translate/test.html";
|
||||
var doc;
|
||||
|
||||
beforeEach(function* () {
|
||||
// This is the main processDocuments, not the translation sandbox one being tested
|
||||
doc = (yield Zotero.HTTP.processDocuments(url, doc => doc))[0];
|
||||
});
|
||||
|
||||
it("should provide document object", async function () {
|
||||
var translate = new Zotero.Translate.Web();
|
||||
translate.setDocument(doc);
|
||||
translate.setTranslator(
|
||||
buildDummyTranslator(
|
||||
4,
|
||||
`function detectWeb() {}
|
||||
function doWeb(doc) {
|
||||
ZU.processDocuments(
|
||||
doc.location.href + '?t',
|
||||
function (doc) {
|
||||
var item = new Zotero.Item("book");
|
||||
item.title = "Container Item";
|
||||
// document.location
|
||||
item.url = doc.location.href;
|
||||
// document.evaluate()
|
||||
item.extra = doc
|
||||
.evaluate('//p', doc, null, XPathResult.ANY_TYPE, null)
|
||||
.iterateNext()
|
||||
.textContent;
|
||||
item.attachments = [{
|
||||
document: doc,
|
||||
title: "Snapshot from Document",
|
||||
note: "attachment note",
|
||||
tags: ${JSON.stringify(TEST_TAGS)}
|
||||
}];
|
||||
item.complete();
|
||||
}
|
||||
);
|
||||
}`
|
||||
)
|
||||
);
|
||||
var newItems = await translate.translate();
|
||||
assert.equal(newItems.length, 1);
|
||||
|
||||
var item = newItems[0];
|
||||
assert.equal(item.getField('url'), url + '?t');
|
||||
assert.include(item.getField('extra'), 'your research sources');
|
||||
|
||||
var containedAttachments = Zotero.Items.get(newItems[0].getAttachments());
|
||||
assert.equal(containedAttachments.length, 1);
|
||||
|
||||
var snapshot = containedAttachments[0];
|
||||
assert.equal(snapshot.getField("url"), url + '?t');
|
||||
assert.equal(snapshot.getNote(), "attachment note");
|
||||
assert.equal(snapshot.attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_URL);
|
||||
assert.equal(snapshot.attachmentContentType, "text/html");
|
||||
checkTestTags(snapshot, true);
|
||||
});
|
||||
|
||||
it("should use loaded document instead of reloading if possible", function* () {
|
||||
var translate = new Zotero.Translate.Web();
|
||||
translate.setDocument(doc);
|
||||
translate.setTranslator(
|
||||
buildDummyTranslator(
|
||||
4,
|
||||
`function detectWeb() {}
|
||||
function doWeb(doc) {
|
||||
ZU.processDocuments(
|
||||
doc.location.href,
|
||||
function (doc) {
|
||||
var item = new Zotero.Item("book");
|
||||
item.title = "Container Item";
|
||||
// document.location
|
||||
item.url = doc.location.href;
|
||||
// document.evaluate()
|
||||
item.extra = doc
|
||||
.evaluate('//p', doc, null, XPathResult.ANY_TYPE, null)
|
||||
.iterateNext()
|
||||
.textContent;
|
||||
item.attachments = [{
|
||||
document: doc,
|
||||
title: "Snapshot from Document",
|
||||
note: "attachment note",
|
||||
tags: ${JSON.stringify(TEST_TAGS)}
|
||||
}];
|
||||
item.complete();
|
||||
}
|
||||
);
|
||||
}`
|
||||
)
|
||||
);
|
||||
var newItems = yield translate.translate();
|
||||
assert.equal(newItems.length, 1);
|
||||
|
||||
var item = newItems[0];
|
||||
assert.equal(item.getField('url'), url);
|
||||
assert.include(item.getField('extra'), 'your research sources');
|
||||
|
||||
var containedAttachments = Zotero.Items.get(newItems[0].getAttachments());
|
||||
assert.equal(containedAttachments.length, 1);
|
||||
|
||||
var snapshot = containedAttachments[0];
|
||||
assert.equal(snapshot.getField("url"), url);
|
||||
assert.equal(snapshot.getNote(), "attachment note");
|
||||
assert.equal(snapshot.attachmentLinkMode, Zotero.Attachments.LINK_MODE_IMPORTED_URL);
|
||||
assert.equal(snapshot.attachmentContentType, "text/html");
|
||||
checkTestTags(snapshot, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("Translators", function () {
|
||||
it("should round-trip child attachment via BibTeX", function* () {
|
||||
var item = yield createDataObject('item');
|
||||
|
|
Loading…
Reference in a new issue