Changes for bookmarklet update to current codebase (#1579)

This commit is contained in:
Adomas Ven 2018-10-04 11:16:31 +03:00 committed by Dan Stillman
parent ec5424d5ae
commit b6065a7af6
6 changed files with 256 additions and 237 deletions

View file

@ -163,7 +163,7 @@ Zotero.Server.Connector.SaveSession = function (id, action, requestData) {
Zotero.Server.Connector.SaveSession.prototype.onProgress = function (item, progress, error) {
if (!item.id) {
if (item.id === null || item.id === undefined) {
throw new Error("ID not provided");
}
@ -230,6 +230,10 @@ Zotero.Server.Connector.SaveSession.prototype.addItems = async function (items)
await this._updateItems(items);
};
Zotero.Server.Connector.SaveSession.prototype.remove = function () {
delete Zotero.Server.Connector.SessionManager._sessions[this.id];
}
/**
* Change the target data for this session and update any items that have already been saved
*/
@ -399,7 +403,7 @@ Zotero.Server.Connector.GetTranslators.prototype = {
// Translator data
var me = this;
if(data.url) {
Zotero.Translators.getWebTranslatorsForLocation(data.url, data.rootUrl).then(function(data) {
Zotero.Translators.getWebTranslatorsForLocation(data.url, data.url).then(function(data) {
sendResponseCallback(200, "application/json",
JSON.stringify(me._serializeTranslators(data[0])));
});
@ -444,63 +448,45 @@ Zotero.Server.Connector.Detect.prototype = {
/**
* Loads HTML into a hidden browser and initiates translator detection
* @param {Object} data POST data or GET query string
* @param {Function} sendResponseCallback function to send HTTP response
*/
init: function(url, data, sendResponseCallback) {
this.sendResponse = sendResponseCallback;
this._parsedPostData = data;
init: async function(requestData) {
try {
var translators = await this.getTranslators(requestData);
} catch (e) {
Zotero.logError(e);
return 500;
}
this._translate = new Zotero.Translate("web");
this._translate.setHandler("translators", function(obj, item) { me._translatorsAvailable(obj, item) });
Zotero.Server.Connector.Data[this._parsedPostData["uri"]] = "<html>"+this._parsedPostData["html"]+"</html>";
this._browser = Zotero.Browser.createHiddenBrowser();
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = ioService.newURI(this._parsedPostData["uri"], "UTF-8", null);
var pageShowCalled = false;
var me = this;
this._translate.setCookieSandbox(new Zotero.CookieSandbox(this._browser,
this._parsedPostData["uri"], this._parsedPostData["cookie"], url.userAgent));
this._browser.addEventListener("DOMContentLoaded", function() {
try {
if(me._browser.contentDocument.location.href == "about:blank") return;
if(pageShowCalled) return;
pageShowCalled = true;
delete Zotero.Server.Connector.Data[me._parsedPostData["uri"]];
// get translators
me._translate.setDocument(me._browser.contentDocument);
me._translate.setLocation(me._parsedPostData["uri"], me._parsedPostData["uri"]);
me._translate.getTranslators();
} catch(e) {
sendResponseCallback(500);
throw e;
}
}, false);
me._browser.loadURI("zotero://connector/"+encodeURIComponent(this._parsedPostData["uri"]));
},
/**
* Callback to be executed when list of translators becomes available. Sends standard
* translator passing properties with proxies where available for translators.
* @param {Zotero.Translate} translate
* @param {Zotero.Translator[]} translators
*/
_translatorsAvailable: function(translate, translators) {
translators = translators.map(function(translator) {
translator = translator.serialize(TRANSLATOR_PASSING_PROPERTIES.concat('proxy'));
translator.proxy = translator.proxy ? translator.proxy.toJSON() : null;
return translator;
});
this.sendResponse(200, "application/json", JSON.stringify(translators));
return [200, "application/json", JSON.stringify(translators)];
},
async getTranslators(requestData) {
var data = requestData.data;
var cookieSandbox = data.uri
? new Zotero.CookieSandbox(
null,
data.uri,
data.cookie || "",
requestData.headers["User-Agent"]
)
: null;
Zotero.Browser.deleteHiddenBrowser(this._browser);
}
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
.createInstance(Components.interfaces.nsIDOMParser);
var doc = parser.parseFromString(`<html>${data.html}</html>`, 'text/html');
doc = Zotero.HTTP.wrapDocument(doc, data.uri);
let translate = this._translate = new Zotero.Translate.Web();
translate.setDocument(doc);
cookieSandbox && translate.setCookieSandbox(cookieSandbox);
return await translate.getTranslators();
},
}
/**
@ -529,20 +515,118 @@ Zotero.Server.Connector.SavePage.prototype = {
/**
* Either loads HTML into a hidden browser and initiates translation, or saves items directly
* to the database
* @param {Object} data POST data or GET query string
* @param {Function} sendResponseCallback function to send HTTP response
*/
init: function(url, data, sendResponseCallback) {
var { library, collection, editable } = Zotero.Server.Connector.getSaveTarget();
// Shouldn't happen as long as My Library exists
if (!library.editable) {
Zotero.logError("Can't add item to read-only library " + library.name);
return sendResponseCallback(500, "application/json", JSON.stringify({ libraryEditable: false }));
}
this.sendResponse = sendResponseCallback;
Zotero.Server.Connector.Detect.prototype.init.apply(this, [url, data, sendResponseCallback])
init: function(requestData) {
return new Zotero.Promise(async function(resolve) {
function sendResponseCallback() {
if (arguments.length > 1) {
return resolve(arguments);
}
return resolve(arguments[0]);
}
var data = requestData.data;
var { library, collection, editable } = Zotero.Server.Connector.getSaveTarget();
var libraryID = library.libraryID;
var targetID = collection ? collection.treeViewID : library.treeViewID;
if (Zotero.Server.Connector.SessionManager.get(data.sessionID)) {
return sendResponseCallback(409, "application/json", JSON.stringify({ error: "SESSION_EXISTS" }));
}
// Shouldn't happen as long as My Library exists
if (!library.editable) {
Zotero.logError("Can't add item to read-only library " + library.name);
return sendResponseCallback(500, "application/json", JSON.stringify({ libraryEditable: false }));
}
var session = Zotero.Server.Connector.SessionManager.create(data.sessionID);
await session.update(targetID);
this.sendResponse = sendResponseCallback;
this._parsedPostData = data;
try {
var translators = await Zotero.Server.Connector.Detect.prototype.getTranslators.call(this, requestData);
} catch(e) {
Zotero.logError(e);
session.remove();
return sendResponseCallback(500);
}
if(!translators.length) {
Zotero.debug(`No translators available for /connector/savePage ${data.uri}`);
session.remove();
return this.sendResponse(500);
}
// set handlers for translation
var me = this;
var translate = this._translate;
translate.setHandler("select", function(obj, item, callback) { return me._selectItems(obj, item, callback) });
let attachmentTitleData = {};
translate.setHandler("itemsDone", function(obj, items) {
if(items.length || me.selectedItems === false) {
items = items.map((item) => {
let o = {
id: item.id,
title: item.title,
itemType: item.itemType,
contentType: item.mimeType,
mimeType: item.mimeType, // TODO: Remove
};
if (item.attachments) {
let id = 0;
for (let attachment of item.attachments) {
attachment.parent = item.id;
attachment.id = id++;
}
o.attachments = item.attachments.map((attachment) => {
// Retaining id and parent info for session progress management
attachmentTitleData[attachment.title] = {id: attachment.id, parent: item.id};
return {
id: session.id + '_' + attachment.id, // TODO: Remove prefix
title: attachment.title,
contentType: attachment.contentType,
mimeType: attachment.mimeType, // TODO: Remove
};
});
};
session.onProgress(item, 100);
return o;
});
me.sendResponse(201, "application/json", JSON.stringify({items}));
} else {
me.sendResponse(500);
session.remove();
}
});
translate.setHandler("attachmentProgress", function(obj, attachment, progress, error) {
if (attachmentTitleData[attachment.title]) {
session.onProgress(Object.assign(
{},
attachment,
attachmentTitleData[attachment.title],
), progress, error);
}
});
translate.setHandler("error", function(obj, err) {
Zotero.logError(err);
sendResponseCallback(500);
session.remove();
});
if (this._parsedPostData.translatorID) {
translate.setTranslator(this._parsedPostData.translatorID);
} else {
translate.setTranslator(translators[0]);
}
let items = await translate.translate({libraryID, collections: collection ? [collection.id] : false});
session.addItems(items);
// Return 'done: true' so the connector stops checking for updates
session.savingDone = true;
}.bind(this));
},
/**
@ -566,51 +650,40 @@ Zotero.Server.Connector.SavePage.prototype = {
// Send "Multiple Choices" HTTP response
this.sendResponse(300, "application/json", JSON.stringify({selectItems: itemList, instanceID: instanceID, uri: this._parsedPostData.uri}));
this.selectedItemsCallback = callback;
},
}
}
/**
* Handle item selection
*
* Accepts:
* selectedItems - a list of items to translate in ID => text format as returned by a selectItems handler
* instanceID - as returned by savePage call
* Returns:
* 201 response code with empty body
*/
Zotero.Server.Connector.SelectItems = function() {};
Zotero.Server.Endpoints["/connector/selectItems"] = Zotero.Server.Connector.SelectItems;
Zotero.Server.Connector.SelectItems.prototype = {
supportedMethods: ["POST"],
supportedDataTypes: ["application/json"],
permitBookmarklet: true,
/**
* Callback to be executed when list of translators becomes available. Opens progress window,
* selects specified translator, and initiates translation.
* @param {Zotero.Translate} translate
* @param {Zotero.Translator[]} translators
* Finishes up translation when item selection is complete
* @param {String} data POST data or GET query string
* @param {Function} sendResponseCallback function to send HTTP response
*/
_translatorsAvailable: function(translate, translators) {
// make sure translatorsAvailable succeded
if(!translators.length) {
Zotero.Browser.deleteHiddenBrowser(this._browser);
this.sendResponse(500);
return;
init: function(data, sendResponseCallback) {
var saveInstance = Zotero.Server.Connector._waitingForSelection[data.instanceID];
saveInstance.sendResponse = sendResponseCallback;
var selectedItems = false;
for(var i in data.selectedItems) {
selectedItems = data.selectedItems;
break;
}
var { library, collection, editable } = Zotero.Server.Connector.getSaveTarget();
var libraryID = library.libraryID;
// set handlers for translation
var me = this;
var jsonItems = [];
translate.setHandler("select", function(obj, item, callback) { return me._selectItems(obj, item, callback) });
translate.setHandler("itemDone", function(obj, item, jsonItem) {
//Zotero.Server.Connector.AttachmentProgressManager.add(jsonItem.attachments);
jsonItems.push(jsonItem);
});
translate.setHandler("attachmentProgress", function(obj, attachment, progress, error) {
//Zotero.Server.Connector.AttachmentProgressManager.onProgress(attachment, progress, error);
});
translate.setHandler("done", function(obj, item) {
Zotero.Browser.deleteHiddenBrowser(me._browser);
if(jsonItems.length || me.selectedItems === false) {
me.sendResponse(201, "application/json", JSON.stringify({items: jsonItems}));
} else {
me.sendResponse(500);
}
});
if (this._parsedPostData.translatorID) {
translate.setTranslator(this._parsedPostData.translatorID);
} else {
translate.setTranslator(translators[0]);
}
translate.translate({libraryID, collections: collection ? [collection.id] : false});
saveInstance.selectedItemsCallback(selectedItems);
}
}
@ -698,6 +771,7 @@ Zotero.Server.Connector.SaveItems.prototype = {
}
catch (e) {
Zotero.logError(e);
session.remove();
resolve(500);
}
});
@ -881,40 +955,6 @@ Zotero.Server.Connector.SaveSnapshot.prototype = {
}
};
/**
* Handle item selection
*
* Accepts:
* selectedItems - a list of items to translate in ID => text format as returned by a selectItems handler
* instanceID - as returned by savePage call
* Returns:
* 201 response code with empty body
*/
Zotero.Server.Connector.SelectItems = function() {};
Zotero.Server.Endpoints["/connector/selectItems"] = Zotero.Server.Connector.SelectItems;
Zotero.Server.Connector.SelectItems.prototype = {
supportedMethods: ["POST"],
supportedDataTypes: ["application/json"],
permitBookmarklet: true,
/**
* Finishes up translation when item selection is complete
* @param {String} data POST data or GET query string
* @param {Function} sendResponseCallback function to send HTTP response
*/
init: function(data, sendResponseCallback) {
var saveInstance = Zotero.Server.Connector._waitingForSelection[data.instanceID];
saveInstance.sendResponse = sendResponseCallback;
var selectedItems = false;
for(var i in data.selectedItems) {
selectedItems = data.selectedItems;
break;
}
saveInstance.selectedItemsCallback(selectedItems);
}
}
/**
*
*
@ -1508,30 +1548,3 @@ Zotero.Server.Connector.IEHack.prototype = {
'</head><body></body></html>');
}
}
// XXX For compatibility with older connectors; to be removed
Zotero.Server.Connector.IncompatibleVersion = function() {};
Zotero.Server.Connector.IncompatibleVersion._errorShown = false
Zotero.Server.Endpoints["/translate/list"] = Zotero.Server.Connector.IncompatibleVersion;
Zotero.Server.Endpoints["/translate/detect"] = Zotero.Server.Connector.IncompatibleVersion;
Zotero.Server.Endpoints["/translate/save"] = Zotero.Server.Connector.IncompatibleVersion;
Zotero.Server.Endpoints["/translate/select"] = Zotero.Server.Connector.IncompatibleVersion;
Zotero.Server.Connector.IncompatibleVersion.prototype = {
supportedMethods: ["POST"],
supportedDataTypes: ["application/json"],
permitBookmarklet: true,
init: function(postData, sendResponseCallback) {
sendResponseCallback(404);
if(Zotero.Server.Connector.IncompatibleVersion._errorShown) return;
Zotero.Utilities.Internal.activate();
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
createInstance(Components.interfaces.nsIPromptService);
ps.alert(null,
Zotero.getString("connector.error.title"),
Zotero.getString("integration.error.incompatibleVersion2",
["Standalone "+Zotero.version, "Connector", "2.999.1"]));
Zotero.Server.Connector.IncompatibleVersion._errorShown = true;
}
};

View file

@ -356,8 +356,7 @@ Zotero.Server.DataListener.prototype._generateResponse = function (status, conte
response += "X-Zotero-Version: "+Zotero.version+"\r\n";
response += "X-Zotero-Connector-API-Version: "+CONNECTOR_API_VERSION+"\r\n";
if (this.origin === ZOTERO_CONFIG.BOOKMARKLET_ORIGIN ||
this.origin === ZOTERO_CONFIG.HTTP_BOOKMARKLET_ORIGIN) {
if (this.origin === ZOTERO_CONFIG.BOOKMARKLET_ORIGIN) {
response += "Access-Control-Allow-Origin: " + this.origin + "\r\n";
response += "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n";
response += "Access-Control-Allow-Headers: Content-Type,X-Zotero-Connector-API-Version,X-Zotero-Version\r\n";

View file

@ -1213,12 +1213,14 @@ Zotero.Translate.Base.prototype = {
if(this._waitingForRPC) {
// Try detect in Zotero Standalone. If this fails, it fails; we shouldn't
// get hung up about it.
let html = this.document.documentElement.innerHTML;
html = html.replace(new RegExp(Zotero.Utilities.quotemeta(ZOTERO_CONFIG.BOOKMARKLET_URL), 'g'), "about:blank");
Zotero.Connector.callMethod(
"detect",
{
uri: this.location.toString(),
cookie: this.document.cookie,
html: this.document.documentElement.innerHTML
html
}).catch(() => false).then(function (rpcTranslators) {
this._waitingForRPC = false;
@ -1652,25 +1654,26 @@ Zotero.Translate.Base.prototype = {
}
}
return this._itemSaver.saveItems(items.slice(), attachmentCallback.bind(this))
.then(function(newItems) {
// Remove attachments not being saved from item.attachments
for(var i=0; i<items.length; i++) {
var item = items[i];
for(var j=0; j<item.attachments.length; j++) {
if(attachmentsWithProgress.indexOf(item.attachments[j]) === -1) {
item.attachments.splice(j--, 1);
return this._itemSaver.saveItems(items.slice(), attachmentCallback.bind(this),
function(newItems) {
this._runHandler("itemsDone", newItems);
// Remove attachments not being saved from item.attachments
for(var i=0; i<items.length; i++) {
var item = items[i];
for(var j=0; j<item.attachments.length; j++) {
if(attachmentsWithProgress.indexOf(item.attachments[j]) === -1) {
item.attachments.splice(j--, 1);
}
}
}
}
// Trigger itemDone events, waiting for them if they return promises
var maybePromises = [];
for(var i=0, nItems = items.length; i<nItems; i++) {
maybePromises.push(this._runHandler("itemDone", newItems[i], items[i]));
}
return Zotero.Promise.all(maybePromises).then(() => newItems);
}.bind(this))
// Trigger itemDone events, waiting for them if they return promises
var maybePromises = [];
for(var i=0, nItems = items.length; i<nItems; i++) {
maybePromises.push(this._runHandler("itemDone", newItems[i], items[i]));
}
return Zotero.Promise.all(maybePromises).then(() => newItems);
}.bind(this))
.then(function (newItems) {
// Specify that itemDone event was dispatched, so that we don't defer
// attachmentProgress notifications anymore
@ -1761,7 +1764,13 @@ Zotero.Translate.Base.prototype = {
*/
"_detectTranslatorsCollected":function() {
Zotero.debug("Translate: All translator detect calls and RPC calls complete:");
this._foundTranslators.sort(function(a, b) { return a.priority-b.priority });
this._foundTranslators.sort(function(a, b) {
// If priority is equal, prioritize translators that run in browser over the client
if (a.priority == b.priority) {
return a.runMode - b.runMode;
}
return a.priority-b.priority;
});
if (this._foundTranslators.length) {
this._foundTranslators.forEach(function(t) {
Zotero.debug("\t" + t.label + ": " + t.priority);
@ -2127,26 +2136,31 @@ Zotero.Translate.Web.prototype.translate = function (options = {}, ...args) {
/**
* Overload _translateTranslatorLoaded to send an RPC call if necessary
*/
Zotero.Translate.Web.prototype._translateTranslatorLoaded = function() {
Zotero.Translate.Web.prototype._translateTranslatorLoaded = async function() {
var runMode = this.translator[0].runMode;
if(runMode === Zotero.Translator.RUN_MODE_IN_BROWSER || this._parentTranslator) {
Zotero.Translate.Base.prototype._translateTranslatorLoaded.apply(this);
} else if(runMode === Zotero.Translator.RUN_MODE_ZOTERO_STANDALONE ||
(runMode === Zotero.Translator.RUN_MODE_ZOTERO_SERVER && Zotero.Connector.isOnline)) {
(runMode === Zotero.Translator.RUN_MODE_ZOTERO_SERVER && await Zotero.Connector.checkIsOnline())) {
var me = this;
Zotero.Connector.callMethod("savePage", {
let html = this.document.documentElement.innerHTML;
html = html.replace(new RegExp(Zotero.Utilities.quotemeta(ZOTERO_CONFIG.BOOKMARKLET_URL), 'g'), "about:blank")
// Higher timeout since translation might take a while if additional HTTP requests are made
Zotero.Connector.callMethod({method: "savePage", timeout: 60*1000}, {
sessionID: this._sessionID,
uri: this.location.toString(),
translatorID: (typeof this.translator[0] === "object"
? this.translator[0].translatorID : this.translator[0]),
cookie: this.document.cookie,
proxy: this._proxy ? this._proxy.toJSON() : null,
html: this.document.documentElement.innerHTML
}).then(obj => me._translateRPCComplete(obj));
html
}).then(me._translateRPCComplete.bind(me), me._translateRPCComplete.bind(me, null));
} else if(runMode === Zotero.Translator.RUN_MODE_ZOTERO_SERVER) {
var me = this;
Zotero.API.createItem({"url":this.document.location.href.toString()},
function(statusCode, response) {
me._translateServerComplete(statusCode, response);
Zotero.API.createItem({"url":this.document.location.href.toString()}).then(function(response) {
me._translateServerComplete(201, response);
}, function(error) {
me._translateServerComplete(error.status, error.responseText);
});
}
}
@ -2154,8 +2168,8 @@ Zotero.Translate.Web.prototype._translateTranslatorLoaded = function() {
/**
* Called when an call to Zotero Standalone for translation completes
*/
Zotero.Translate.Web.prototype._translateRPCComplete = function(obj, failureCode) {
if(!obj) this.complete(false, failureCode);
Zotero.Translate.Web.prototype._translateRPCComplete = async function(obj, failureCode) {
if(!obj) return this.complete(false, failureCode);
if(obj.selectItems) {
// if we have to select items, call the selectItems handler and do it
@ -2173,6 +2187,17 @@ Zotero.Translate.Web.prototype._translateRPCComplete = function(obj, failureCode
this._runHandler("itemDone", null, obj.items[i]);
}
this.newItems = obj.items;
let itemSaver = new Zotero.Translate.ItemSaver({
libraryID: this._libraryID,
collections: this._collections,
attachmentMode: Zotero.Translate.ItemSaver[(this._saveAttachments ? "ATTACHMENT_MODE_DOWNLOAD" : "ATTACHMENT_MODE_IGNORE")],
forceTagType: 1,
sessionID: this._sessionID,
cookieSandbox: this._cookieSandbox,
proxy: this._proxy,
baseURI: this.location
});
await itemSaver._pollForProgress(obj.items, this._runHandler.bind(this, 'attachmentProgress'));
this.complete(true);
}
}
@ -2191,56 +2216,39 @@ Zotero.Translate.Web.prototype._translateServerComplete = function(statusCode, r
return;
}
var me = this;
this._runHandler("select", response,
this._runHandler("select", response.items,
function(selectedItems) {
Zotero.API.createItem({
"url":me.document.location.href.toString(),
"items":selectedItems
},
function(statusCode, response) {
me._translateServerComplete(statusCode, response);
});
url: me.document.location.href.toString(),
items: selectedItems,
token: response.token
}).then(function(response) {
me._translateServerComplete(201, response);
}, function(error) {
me._translateServerComplete(error.status, error.responseText);
});
}
);
} else if(statusCode === 201) {
// Created
try {
response = (new DOMParser()).parseFromString(response, "application/xml");
response = JSON.parse(response);
} catch(e) {
Zotero.logError(e);
this.complete(false, "Invalid XML response received from server");
this.complete(false, "Invalid JSON response received from server");
return;
}
// Extract items from ATOM/JSON response
var items = [], contents;
if("getElementsByTagNameNS" in response) {
contents = response.getElementsByTagNameNS("http://www.w3.org/2005/Atom", "content");
} else { // IE...
contents = response.getElementsByTagName("content");
}
for(var i=0, n=contents.length; i<n; i++) {
var content = contents[i];
if("getAttributeNS" in content) {
if(content.getAttributeNS("http://zotero.org/ns/api", "type") != "json") continue;
} else if(content.getAttribute("zapi:type") != "json") { // IE...
continue;
}
try {
var item = JSON.parse("textContent" in content ?
content.textContent : content.text);
} catch(e) {
Zotero.logError(e);
this.complete(false, "Invalid JSON response received from server");
return;
}
let items = [];
for (let key in response.successful) {
var item = response.successful[key].data;
if(!("attachments" in item)) item.attachments = [];
this._runHandler("itemDone", null, item);
items.push(item);
}
this.newItems = items;
this._runHandler("itemsDone", null, item);
this.complete(true);
} else {
this.complete(false, response);
@ -2266,7 +2274,7 @@ Zotero.Translate.Web.prototype.complete = async function(returnValue, error) {
if(oldState == "translate" && errorString && !this._parentTranslator && this.translator.length
&& this.translator[0].inRepository && reportTranslationFailure) {
// Don't report failure if in private browsing mode
if (Zotero.isConnector && await Zotero.Connector_Browser.isIncognito()) {
if (Zotero.isConnector && !Zotero.isBookmarklet && await Zotero.Connector_Browser.isIncognito()) {
return
}

View file

@ -177,6 +177,10 @@ Zotero.Translate.ItemSaver.prototype = {
jsonByItem.set(item, jsonItem);
}
}.bind(this));
if (itemsDoneCallback) {
itemsDoneCallback(items.map(item => jsonByItem.get(item)));
}
// Save standalone attachments
for (let jsonItem of standaloneAttachments) {
@ -186,10 +190,6 @@ Zotero.Translate.ItemSaver.prototype = {
}
}
if (itemsDoneCallback) {
itemsDoneCallback(items.map(item => jsonByItem.get(item)));
}
// For items with DOIs and without PDFs from the translator, look for possible
// open-access PDFs. There's no guarantee that either translated PDFs or OA PDFs will
// successfully download, but this lets us update the progress window sooner with

View file

@ -326,7 +326,7 @@ Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, res
translate.incrementAsyncProcesses("Zotero.Utilities.Translate#doGet");
var xmlhttp = Zotero.HTTP.doGet(url, function(xmlhttp) {
if (xmlhttp.status >= 400) {
if (xmlhttp.status >= 400 || !xmlhttp.status) {
translate.complete(false, `HTTP GET ${url} failed with status code ${xmlhttp.status}`);
return;
}
@ -360,7 +360,7 @@ Zotero.Utilities.Translate.prototype.doPost = function(url, body, onDone, header
translate.incrementAsyncProcesses("Zotero.Utilities.Translate#doPost");
var xmlhttp = Zotero.HTTP.doPost(url, body, function(xmlhttp) {
if (xmlhttp.status >= 400) {
if (xmlhttp.status >= 400 || !xmlhttp.status) {
translate.complete(false, `HTTP POST ${url} failed with status code ${xmlhttp.status}`);
return;
}

View file

@ -17,7 +17,6 @@ var ZOTERO_CONFIG = {
CONNECTOR_MIN_VERSION: '5.0.39', // show upgrade prompt for requests from below this version
PREF_BRANCH: 'extensions.zotero.',
BOOKMARKLET_ORIGIN: 'https://www.zotero.org',
HTTP_BOOKMARKLET_ORIGIN: 'http://www.zotero.org',
BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/',
START_URL: "https://www.zotero.org/start",
QUICK_START_URL: "https://www.zotero.org/support/quick_start_guide",