commit 4666ae972ccd713369436e2b582b5d778ec821b1
parent 21254238e1a22ecca74689e83ad82c7a90ddc9a9
Author: Simon Kornblith <simon@simonster.com>
Date: Wed, 31 Aug 2011 23:25:48 +0000
- Move Zotero.Utilities.Internal and Zotero.Utilities.Translate to separate files
- IE compatibility for translation core
Diffstat:
10 files changed, 764 insertions(+), 711 deletions(-)
diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js
@@ -615,7 +615,7 @@ var Zotero_File_Interface = new function() {
* Updates progress indicators based on current progress of translation
*/
this.updateProgress = function(translate) {
- Zotero.updateZoteroPaneProgressMeter(translate.progress);
+ Zotero.updateZoteroPaneProgressMeter(translate.getProgress());
}
}
diff --git a/chrome/content/zotero/xpcom/connector/translate_item.js b/chrome/content/zotero/xpcom/connector/translate_item.js
@@ -64,10 +64,9 @@ Zotero.Translate.ItemSaver.prototype = {
var url = 'users/%%USERID%%/items?key=%%APIKEY%%';
var payload = JSON.stringify({"items":newItems}, null, "\t")
- Zotero.OAuth.doAuthenticatedPost(url, payload, function(status, message) {
+ Zotero.OAuth.doAuthenticatedPost(url, payload, function(status) {
if(!status) {
- Zotero.debug("Translate: Save to server failed with message "+message+"; payload:\n\n"+payload);
- callback(false, new Error("Save to server failed with "+message));
+ callback(false, new Error("Save to server failed"));
} else {
Zotero.debug("Translate: Save to server complete");
callback(true, newItems);
diff --git a/chrome/content/zotero/xpcom/date.js b/chrome/content/zotero/xpcom/date.js
@@ -50,7 +50,9 @@ Zotero.Date = new function(){
/**
* Load dateFormat bundle into _dateFormatsBundle
*/
- function _loadDateFormatsBundle() {
+ this.getMonths = function() {
+ if(_months) return _months;
+
if(Zotero.isFx) {
var src = 'chrome://global/locale/dateFormat.properties';
var localeService = Components.classes['@mozilla.org/intl/nslocaleservice;1'].
@@ -74,15 +76,9 @@ Zotero.Date = new function(){
"long":["January", "February", "March", "April", "May", "June", "July",
"Auguest", "September", "October", "November", "December"]};
}
- }
-
- /**
- * Lazy getter for reading month strings from dateFormat.properties
- */
- this.__defineGetter__("months", function() {
- if(!_months) _loadDateFormatsBundle();
+
return _months;
- });
+ }
/**
* Convert an SQL date in the form '2006-06-13 11:03:05' into a JS Date object
@@ -346,7 +342,8 @@ Zotero.Date = new function(){
'aug', 'sep', 'oct', 'nov', 'dec'];
// If using a non-English bibliography locale, try those too
if (Zotero.locale != 'en-US') {
- months = months.concat(Zotero.Date.months.short).concat(Zotero.Date.months.long);
+ Zotero.Date.getMonths();
+ months = months.concat(_months['short']).concat(_months['long']);
for(var i in months) months[i] = months[i].toLowerCase();
}
@@ -425,7 +422,7 @@ Zotero.Date = new function(){
string += date.part+" ";
}
- var months = Zotero.Date.months.long;
+ var months = Zotero.Date.getMonths().long;
if(date.month != undefined && months[date.month]) {
// get short month strings from CSL interpreter
string += months[date.month];
diff --git a/chrome/content/zotero/xpcom/debug.js b/chrome/content/zotero/xpcom/debug.js
@@ -25,12 +25,12 @@
Zotero.Debug = new function () {
- this.__defineGetter__('storing', function () { return _store; });
- this.__defineGetter__('enabled', function () { return _console || _store; });
-
var _console, _stackTrace, _store, _level, _time, _lastTime, _output = [];
this.init = function () {
+ this.storing = _store;
+ this.enabled = _console || _store;
+
_console = Zotero.Prefs.get('debug.log');
_store = Zotero.Prefs.get('debug.store');
if (_store) {
@@ -133,6 +133,9 @@ Zotero.Debug = new function () {
this.clear();
}
_store = enable;
+
+ this.storing = _store;
+ this.enabled = _console || _store;
}
diff --git a/chrome/content/zotero/xpcom/translation/translate.js b/chrome/content/zotero/xpcom/translation/translate.js
@@ -1026,6 +1026,11 @@ Zotero.Translate.Base.prototype = {
},
/**
+ * Return the progress of the import operation, or null if progress cannot be determined
+ */
+ "getProgress":function() { return null },
+
+ /**
* Executed on translator completion, either automatically from a synchronous scraper or as
* done() from an asynchronous scraper. Finishes things up and calls callback function(s).
* @param {Boolean|String} returnValue An item type or a boolean true or false
@@ -1322,7 +1327,7 @@ Zotero.Translate.Base.prototype = {
/**
* No-op for preparing translation
*/
- "_prepareTranslation":function() {},
+ "_prepareTranslation":function() {}
}
/**
@@ -1622,17 +1627,16 @@ Zotero.Translate.Import.prototype._prepareTranslation = function() {
this.newCollections = [];
}
-Zotero.Translate.Import.prototype.__defineGetter__("progress",
/**
* Return the progress of the import operation, or null if progress cannot be determined
*/
-function() {
+Zotero.Translate.Import.prototype.getProgress = function() {
if(this._progress !== undefined) return this._progress;
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1 || this._mode === "xml/e4x" || this._mode == "xml/dom" || !this._io) {
return null;
}
return this._io.bytesRead/this._io.contentLength*100;
-});
+};
/**
@@ -1686,9 +1690,20 @@ Zotero.Translate.Export.prototype.setDisplayOptions = function(displayOptions) {
}
/**
- * @borrows Zotero.Translate.Import#complete
+ * Overload {@link Zotero.Translate.Base#complete} to close file and set complete
*/
-Zotero.Translate.Export.prototype.complete = Zotero.Translate.Import.prototype.complete;
+Zotero.Translate.Export.prototype.complete = function(returnValue, error) {
+ if(this._io) {
+ this._progress = null;
+ this._io.close();
+ if(this._io instanceof Zotero.Translate.IO.String) {
+ this.string = this._io.string;
+ }
+ }
+
+ // call super
+ Zotero.Translate.Base.prototype.complete.apply(this, [returnValue, error]);
+}
/**
* Overload {@link Zotero.Translate.Base#getTranslators} to return all translators immediately
@@ -1730,9 +1745,8 @@ Zotero.Translate.Export.prototype._prepareTranslation = function() {
// this is currently hackish since we pass null callbacks to the init function (they have
// callbacks to be consistent with import, but they are synchronous, so we ignore them)
if(!this.location) {
- var io = this._io = new Zotero.Translate.IO.String(null, this.path ? this.path : "");
- io.init(this.translator[0].configOptions["dataMode"], function() {});
- this.__defineGetter__("string", function() { return io.string; });
+ this._io = new Zotero.Translate.IO.String(null, this.path ? this.path : "");
+ this._io.init(this.translator[0].configOptions["dataMode"], function() {});
} else if(!Zotero.Translate.IO.Write) {
throw new Error("Writing to files is not supported in this build of Zotero.");
} else {
@@ -1745,17 +1759,16 @@ Zotero.Translate.Export.prototype._prepareTranslation = function() {
this._sandboxManager.importObject(this._io);
}
-Zotero.Translate.Export.prototype.__defineGetter__("progress",
/**
* Return the progress of the import operation, or null if progress cannot be determined
*/
-function() {
+Zotero.Translate.Export.prototype.getProgress = function() {
if(this._progress !== undefined) return this._progress;
if(!this._itemGetter) {
return null;
}
return (1-this._itemGetter.numItemsRemaining/this._itemGetter.numItems)*100;
-});
+};
/**
* @class Search translation
@@ -1901,11 +1914,12 @@ Zotero.Translate.IO = {
*/
Zotero.Translate.IO.String = function(string, uri, mode) {
if(string && typeof string === "string") {
- this._string = string;
+ this.string = string;
} else {
- this._string = "";
+ this.string = "";
}
- this._stringPointer = 0;
+ this.contentLength = this.string.length;
+ this.bytesRead = 0;
this._uri = uri;
}
@@ -1923,9 +1937,9 @@ Zotero.Translate.IO.String.prototype = {
this._dataStore = new Zotero.RDF.AJAW.RDFIndexedFormula();
this.RDF = new Zotero.Translate.IO._RDFSandbox(this._dataStore);
- if(this._string.length) {
+ if(this.contentLength) {
try {
- var xml = Zotero.Translate.IO.parseDOMXML(this._string);
+ var xml = Zotero.Translate.IO.parseDOMXML(this.string);
} catch(e) {
this._xmlInvalid = true;
throw e;
@@ -1941,68 +1955,69 @@ Zotero.Translate.IO.String.prototype = {
"read":function(bytes) {
// if we are reading in RDF data mode and no string is set, serialize current RDF to the
// string
- if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1 && this._string === "") {
- this._string = this.RDF.serialize();
+ if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1 && this.string === "") {
+ this.string = this.RDF.serialize();
}
// return false if string has been read
- if(this._stringPointer >= this._string.length) {
+ if(this.bytesRead >= this.contentLength) {
return false;
}
if(bytes !== undefined) {
- if(this._stringPointer >= this._string.length) return false;
- var oldPointer = this._stringPointer;
- this._stringPointer += bytes;
- return this._string.substr(oldPointer, bytes);
+ if(this.bytesRead >= this.contentLength) return false;
+ var oldPointer = this.bytesRead;
+ this.bytesRead += bytes;
+ return this.string.substr(oldPointer, bytes);
} else {
// bytes not specified; read a line
- var oldPointer = this._stringPointer;
- var lfIndex = this._string.indexOf("\n", this._stringPointer);
+ var oldPointer = this.bytesRead;
+ var lfIndex = this.string.indexOf("\n", this.bytesRead);
if(lfIndex !== -1) {
// in case we have a CRLF
- this._stringPointer = lfIndex+1;
- if(this._string.length > lfIndex && this._string[lfIndex-1] === "\r") {
+ this.bytesRead = lfIndex+1;
+ if(this.contentLength > lfIndex && this.string[lfIndex-1] === "\r") {
lfIndex--;
}
- return this._string.substr(oldPointer, lfIndex-oldPointer);
+ return this.string.substr(oldPointer, lfIndex-oldPointer);
}
if(!this._noCR) {
- var crIndex = this._string.indexOf("\r", this._stringPointer);
+ var crIndex = this.string.indexOf("\r", this.bytesRead);
if(crIndex === -1) {
this._noCR = true;
} else {
- this._stringPointer = crIndex+1;
- return this._string.substr(oldPointer, crIndex-oldPointer-1);
+ this.bytesRead = crIndex+1;
+ return this.string.substr(oldPointer, crIndex-oldPointer-1);
}
}
- this._stringPointer = this._string.length;
- return this._string.substr(oldPointer);
+ this.bytesRead = this.contentLength;
+ return this.string.substr(oldPointer);
}
},
"write":function(data) {
- this._string += data;
+ this.string += data;
+ this.contentLength = this.string.length;
},
"_getXML":function() {
if(this._mode == "xml/dom") {
try {
- return Zotero.Translate.IO.parseDOMXML(this._string);
+ return Zotero.Translate.IO.parseDOMXML(this.string);
} catch(e) {
this._xmlInvalid = true;
throw e;
}
} else {
- return this._string.replace(/<\?xml[^>]+\?>/, "");
+ return this.string.replace(/<\?xml[^>]+\?>/, "");
}
},
"init":function(newMode, callback) {
- this._stringPointer = 0;
+ this.bytesRead = 0;
this._noCR = undefined;
this._mode = newMode;
@@ -2018,26 +2033,6 @@ Zotero.Translate.IO.String.prototype = {
"close":function() {}
}
-Zotero.Translate.IO.String.prototype.__defineGetter__("string",
-function() {
- if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1) {
- return this.RDF.serialize();
- } else {
- return this._string;
- }
-});
-Zotero.Translate.IO.String.prototype.__defineSetter__("string",
-function(string) {
- this._string = string;
-});
-Zotero.Translate.IO.String.prototype.__defineGetter__("bytesRead",
-function() {
- return this._stringPointer;
-});
-Zotero.Translate.IO.String.prototype.__defineGetter__("contentLength",
-function() {
- return this._string.length;
-});
/****** RDF DATA MODE ******/
diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js
@@ -1084,635 +1084,4 @@ Zotero.Utilities = {
return newItem;
}
-}
-
-/**
- * @class All functions accessible from within Zotero.Utilities namespace inside sandboxed
- * translators
- *
- * @constructor
- * @augments Zotero.Utilities
- * @borrows Zotero.Date.formatDate as this.formatDate
- * @borrows Zotero.Date.strToDate as this.strToDate
- * @borrows Zotero.Date.strToISO as this.strToISO
- * @borrows Zotero.OpenURL.createContextObject as this.createContextObject
- * @borrows Zotero.OpenURL.parseContextObject as this.parseContextObject
- * @borrows Zotero.HTTP.processDocuments as this.processDocuments
- * @borrows Zotero.HTTP.doPost as this.doPost
- * @param {Zotero.Translate} translate
- */
-Zotero.Utilities.Translate = function(translate) {
- this._translate = translate;
-}
-
-var tmp = function() {};
-tmp.prototype = Zotero.Utilities;
-Zotero.Utilities.Translate.prototype = new tmp();
-Zotero.Utilities.Translate.prototype.formatDate = Zotero.Date.formatDate;
-Zotero.Utilities.Translate.prototype.strToDate = Zotero.Date.strToDate;
-Zotero.Utilities.Translate.prototype.strToISO = Zotero.Date.strToISO;
-Zotero.Utilities.Translate.prototype.createContextObject = Zotero.OpenURL.createContextObject;
-Zotero.Utilities.Translate.prototype.parseContextObject = Zotero.OpenURL.parseContextObject;
-
-/**
- * Hack to overloads {@link Zotero.Utilities.capitalizeTitle} to allow overriding capitalizeTitles
- * pref on a per-translate instance basis (for translator testing only)
- */
-Zotero.Utilities.Translate.prototype.capitalizeTitle = function(string, force) {
- if(force === undefined) {
- var translate = this._translate;
- do {
- if(translate.capitalizeTitles !== undefined) {
- force = translate.capitalizeTitles;
- break;
- }
- } while(translate = translate._parentTranslator);
- }
-
- return Zotero.Utilities.capitalizeTitle(string, force);
-}
-
-/**
- * Gets the current Zotero version
- *
- * @type String
- */
-Zotero.Utilities.Translate.prototype.getVersion = function() {
- return Zotero.version;
-}
-
-/**
- * Takes an XPath query and returns the results
- *
- * @deprecated Use {@link Zotero.Utilities.xpath} or doc.evaluate() directly
- * @type Node[]
- */
-Zotero.Utilities.Translate.prototype.gatherElementsOnXPath = function(doc, parentNode, xpath, nsResolver) {
- var elmts = [];
-
- var iterator = doc.evaluate(xpath, parentNode, nsResolver,
- (Zotero.isFx ? Components.interfaces.nsIDOMXPathResult.ANY_TYPE : XPathResult.ANY_TYPE),
- null);
- var elmt = iterator.iterateNext();
- var i = 0;
- while (elmt) {
- elmts[i++] = elmt;
- elmt = iterator.iterateNext();
- }
- return elmts;
-}
-
-/**
- * Gets a given node as a string containing all child nodes
- *
- * @deprecated Use doc.evaluate and the "nodeValue" or "textContent" property
- * @type String
- */
-Zotero.Utilities.Translate.prototype.getNodeString = function(doc, contextNode, xpath, nsResolver) {
- var elmts = this.gatherElementsOnXPath(doc, contextNode, xpath, nsResolver);
- var returnVar = "";
- for(var i=0; i<elmts.length; i++) {
- returnVar += elmts[i].nodeValue;
- }
- return returnVar;
-}
-
-/**
- * Grabs items based on URLs
- *
- * @param {Document} doc DOM document object
- * @param {Element|Element[]} inHere DOM element(s) to process
- * @param {RegExp} [urlRe] Regexp of URLs to add to list
- * @param {RegExp} [urlRe] Regexp of URLs to reject
- * @return {Object} Associative array of link => textContent pairs, suitable for passing to
- * Zotero.selectItems from within a translator
- */
-Zotero.Utilities.Translate.prototype.getItemArray = function(doc, inHere, urlRe, rejectRe) {
- var availableItems = new Object(); // Technically, associative arrays are objects
-
- // Require link to match this
- if(urlRe) {
- if(urlRe.exec) {
- var urlRegexp = urlRe;
- } else {
- var urlRegexp = new RegExp();
- urlRegexp.compile(urlRe, "i");
- }
- }
- // Do not allow text to match this
- if(rejectRe) {
- if(rejectRe.exec) {
- var rejectRegexp = rejectRe;
- } else {
- var rejectRegexp = new RegExp();
- rejectRegexp.compile(rejectRe, "i");
- }
- }
-
- if(!inHere.length) {
- inHere = new Array(inHere);
- }
-
- for(var j=0; j<inHere.length; j++) {
- var links = inHere[j].getElementsByTagName("a");
- for(var i=0; i<links.length; i++) {
- if(!urlRe || urlRegexp.test(links[i].href)) {
- var text = links[i].textContent;
- if(text) {
- text = this.trimInternal(text);
- if(!rejectRe || !rejectRegexp.test(text)) {
- if(availableItems[links[i].href]) {
- if(text != availableItems[links[i].href]) {
- availableItems[links[i].href] += " "+text;
- }
- } else {
- availableItems[links[i].href] = text;
- }
- }
- }
- }
- }
- }
-
- return availableItems;
-}
-
-
-/**
- * Load a single document in a hidden browser
- *
- * @deprecated Use processDocuments with a single URL
- * @see Zotero.Utilities.Translate#processDocuments
- */
-Zotero.Utilities.Translate.prototype.loadDocument = function(url, succeeded, failed) {
- Zotero.debug("Zotero.Utilities.loadDocument is deprecated; please use processDocuments in new code");
- this.processDocuments([url], succeeded, null, failed);
-}
-
-/**
- * Already documented in Zotero.HTTP
- * @ignore
- */
-Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor, done, exception) {
- if(typeof(urls) == "string") {
- urls = [this._convertURL(urls)];
- } else {
- for(var i in urls) {
- urls[i] = this._convertURL(urls[i]);
- }
- }
-
- // Unless the translator has proposed some way to handle an error, handle it
- // by throwing a "scraping error" message
- var translate = this._translate;
- if(exception) {
- var myException = function(e) {
- try {
- exception(e);
- } catch(e) {
- try {
- Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
- } catch(e) {}
- translate.complete(false, e);
- }
- }
- } else {
- var myException = function(e) {
- try {
- Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
- } catch(e) {}
- translate.complete(false, e);
- }
- }
-
- var translate = this._translate;
- translate.incrementAsyncProcesses();
- var hiddenBrowser = Zotero.HTTP.processDocuments(urls, processor, function() {
- if(done) done();
- translate.decrementAsyncProcesses();
- translate.setHandler("done", function() {
- try {
- Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
- } catch(e) {}
- });
- }, myException, true, translate.cookieSandbox);
-}
-
-/**
- * Gets the DOM document object corresponding to the page located at URL, but avoids locking the
- * UI while the request is in process.
- *
- * @param {String} url URL to load
- * @return {Document} DOM document object
- */
-Zotero.Utilities.Translate.prototype.retrieveDocument = function(url) {
- if(!Zotero.isFx) throw "Zotero.Utilities.retrieveDocument() is unsupported outside of Firefox";
- this._translate._debug("WARNING: Zotero.Utilities.retrieveDocument() is unsupported outside of Firefox", 1);
-
- url = this._convertURL(url);
-
- var mainThread = Zotero.mainThread;
- var loaded = false;
- var listener = function() {
- loaded = hiddenBrowser.contentDocument.location.href != "about:blank";
- }
-
- var hiddenBrowser = Zotero.Browser.createHiddenBrowser();
- if(translate.cookieSandbox) translate.cookieSandbox.attachToBrowser(hiddenBrowser);
-
- hiddenBrowser.addEventListener("pageshow", listener, true);
- hiddenBrowser.loadURI(url);
-
- // Use a timeout of 2 minutes. Without a timeout, a request to an IP at which no system is
- // configured will continue indefinitely, and hang Firefox as it shuts down. No same request
- // should ever take longer than 2 minutes.
- var endTime = Date.now() + 120000;
- while(!loaded && Date.now() < endTime) {
- mainThread.processNextEvent(true);
- }
-
- hiddenBrowser.removeEventListener("pageshow", listener, true);
- hiddenBrowser.contentWindow.setTimeout(function() {
- Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
- }, 1);
-
- if(!loaded) throw "retrieveDocument failed: request timeout";
- return hiddenBrowser.contentDocument;
-}
-
-/**
- * Gets the source of the page located at URL, but avoids locking the UI while the request is in
- * process.
- *
- * @param {String} url URL to load
- * @param {String} [body=null] Request body to POST to the URL; a GET request is
- * executed if no body is present
- * @param {Object} [headers] HTTP headers to include in request;
- * Content-Type defaults to application/x-www-form-urlencoded
- * for POST; ignored if no body
- * @param {String} [responseCharset] Character set to force on the response
- * @return {String} Request body
- */
-Zotero.Utilities.Translate.prototype.retrieveSource = function(url, body, headers, responseCharset) {
- this._translate._debug("WARNING: Use of Zotero.Utilities.retrieveSource() is deprecated. "+
- "The main thread will be frozen when Zotero.Utilities.retrieveSource() is called outside "+
- "of Firefox, and cross-domain requests will not work.", 1);
-
- if(Zotero.isFx) {
- /* Apparently, a synchronous XMLHttpRequest would have the behavior of this routine in FF3, but
- * in FF3.5, synchronous XHR blocks all JavaScript on the thread. See
- * http://hacks.mozilla.org/2009/07/synchronous-xhr/. */
- url = this._convertURL(url);
- if(!headers) headers = null;
- if(!responseCharset) responseCharset = null;
-
- var mainThread = Zotero.mainThread;
- var finished = false;
- var listener = function() { finished = true };
-
- if(body) {
- var xmlhttp = Zotero.HTTP.doPost(url, body, listener, headers, responseCharset, translate.cookieSandbox);
- } else {
- var xmlhttp = Zotero.HTTP.doGet(url, listener, responseCharset, translate.cookieSandbox);
- }
-
- while(!finished) mainThread.processNextEvent(true);
- } else {
- // Use a synchronous XMLHttpRequest, even though this is inadvisable
- var xmlhttp = new XMLHttpRequest();
- xmlhttp.open((body ? "POST" : "GET"), url, false);
- xmlhttp.send(body ? body : null);
- }
-
- if(xmlhttp.status >= 400) throw "Zotero.Utilities.retrieveSource() failed: "+xmlhttp.status+" "+xmlhttp.statusText;
-
- return xmlhttp.responseText;
-}
-
-/**
-* Send an HTTP GET request via XMLHTTPRequest
-*
-* @param {String|String[]} urls URL(s) to request
-* @param {Function} processor Callback to be executed for each document loaded
-* @param {Function} done Callback to be executed after all documents have been loaded
-* @param {String} responseCharset Character set to force on the response
-* @return {Boolean} True if the request was sent, or false if the browser is offline
-*/
-Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, responseCharset) {
- var callAgain = false;
-
- if(typeof(urls) == "string") {
- var url = urls;
- } else {
- if(urls.length > 1) callAgain = true;
- var url = urls.shift();
- }
-
- url = this._convertURL(url);
-
- var me = this;
-
- this._translate.incrementAsyncProcesses();
- var xmlhttp = Zotero.HTTP.doGet(url, function(xmlhttp) {
- try {
- if(processor) {
- processor(xmlhttp.responseText, xmlhttp, url);
- }
-
- if(callAgain) {
- me.doGet(urls, processor, done);
- } else {
- if(done) {
- done();
- }
- }
- me._translate.decrementAsyncProcesses();
- } catch(e) {
- me._translate.complete(false, e);
- }
- }, responseCharset, this._translate.cookieSandbox);
-}
-
-/**
- * Already documented in Zotero.HTTP
- * @ignore
- */
-Zotero.Utilities.Translate.prototype.doPost = function(url, body, onDone, headers, responseCharset) {
- url = this._convertURL(url);
-
- var translate = this._translate;
- this._translate.incrementAsyncProcesses();
- var xmlhttp = Zotero.HTTP.doPost(url, body, function(xmlhttp) {
- try {
- onDone(xmlhttp.responseText, xmlhttp);
- translate.decrementAsyncProcesses();
- } catch(e) {
- translate.complete(false, e);
- }
- }, headers, responseCharset, translate.cookieSandbox ? translate.cookieSandbox : undefined);
-}
-
-/**
- * Translate a URL to a form that goes through the appropriate proxy, or convert a relative URL to
- * an absolute one
- *
- * @param {String} url
- * @type String
- * @private
- */
-Zotero.Utilities.Translate.prototype._convertURL = function(url) {
- const protocolRe = /^(?:(?:http|https|ftp):)/i;
-
- // convert proxy to proper if applicable
- if(protocolRe.test(url)) {
- if(this._translate.translator && this._translate.translator[0]
- && this._translate.translator[0].properToProxy) {
- url = this._translate.translator[0].properToProxy(url);
- }
- return url;
- }
-
- // resolve local URL
- var resolved = "";
- if(Zotero.isFx) {
- resolved = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService).
- newURI(this._translate.location, "", null).resolve(url);
- } else if(Zotero.isChrome || Zotero.isSafari) {
- var a = document.createElement('a');
- a.href = url;
- resolved = a.href;
- } else if(Zotero.isNode) {
- resolved = require('url').resolve(this._translate.location, url);
- }
-
- if(!protocolRe.test(resolved)) {
- throw new Error("Invalid URL supplied for HTTP request: "+url);
- }
-
- return resolved;
-}
-
-Zotero.Utilities.Translate.prototype.__exposedProps__ = {"HTTP":"r"};
-for(var j in Zotero.Utilities.Translate.prototype) {
- if(typeof Zotero.Utilities.Translate.prototype[j] === "function" && j[0] !== "_" && j != "Translate") {
- Zotero.Utilities.Translate.prototype.__exposedProps__[j] = "r";
- }
-}
-
-/**
- * @class Utility functions not made available to translators
- */
-Zotero.Utilities.Internal = {
- /*
- * Adapted from http://developer.mozilla.org/en/docs/nsICryptoHash
- *
- * @param {String|nsIFile} strOrFile
- * @param {Boolean} [base64=false] Return as base-64-encoded string rather than hex string
- * @return {String}
- */
- "md5":function(strOrFile, base64) {
- if (typeof strOrFile == 'string') {
- var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
- createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
- converter.charset = "UTF-8";
- var result = {};
- var data = converter.convertToByteArray(strOrFile, result);
- var ch = Components.classes["@mozilla.org/security/hash;1"]
- .createInstance(Components.interfaces.nsICryptoHash);
- ch.init(ch.MD5);
- ch.update(data, data.length);
- }
- else if (strOrFile instanceof Components.interfaces.nsIFile) {
- // Otherwise throws (NS_ERROR_NOT_AVAILABLE) [nsICryptoHash.updateFromStream]
- if (!strOrFile.fileSize) {
- // MD5 for empty string
- return "d41d8cd98f00b204e9800998ecf8427e";
- }
-
- var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Components.interfaces.nsIFileInputStream);
- // open for reading
- istream.init(strOrFile, 0x01, 0444, 0);
- var ch = Components.classes["@mozilla.org/security/hash;1"]
- .createInstance(Components.interfaces.nsICryptoHash);
- // we want to use the MD5 algorithm
- ch.init(ch.MD5);
- // this tells updateFromStream to read the entire file
- const PR_UINT32_MAX = 0xffffffff;
- ch.updateFromStream(istream, PR_UINT32_MAX);
- }
-
- // pass false here to get binary data back
- var hash = ch.finish(base64);
-
- if (istream) {
- istream.close();
- }
-
- if (base64) {
- return hash;
- }
-
- /*
- // This created 36-character hashes
-
- // return the two-digit hexadecimal code for a byte
- function toHexString(charCode) {
- return ("0" + charCode.toString(16)).slice(-2);
- }
-
- // convert the binary hash data to a hex string.
- return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
- */
-
- // From http://rcrowley.org/2007/11/15/md5-in-xulrunner-or-firefox-extensions/
- var ascii = [];
- var ii = hash.length;
- for (var i = 0; i < ii; ++i) {
- var c = hash.charCodeAt(i);
- var ones = c % 16;
- var tens = c >> 4;
- ascii.push(String.fromCharCode(tens + (tens > 9 ? 87 : 48)) + String.fromCharCode(ones + (ones > 9 ? 87 : 48)));
- }
- return ascii.join('');
- }
-}
-
-/**
- * Base64 encode / decode
- * From http://www.webtoolkit.info/
- */
-Zotero.Utilities.Internal.Base64 = {
- // private property
- _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
-
- // public method for encoding
- encode : function (input) {
- var output = "";
- var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
- var i = 0;
-
- input = this._utf8_encode(input);
-
- while (i < input.length) {
-
- chr1 = input.charCodeAt(i++);
- chr2 = input.charCodeAt(i++);
- chr3 = input.charCodeAt(i++);
-
- enc1 = chr1 >> 2;
- enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
- enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
- enc4 = chr3 & 63;
-
- if (isNaN(chr2)) {
- enc3 = enc4 = 64;
- } else if (isNaN(chr3)) {
- enc4 = 64;
- }
-
- output = output +
- this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
- this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
-
- }
-
- return output;
- },
-
- // public method for decoding
- decode : function (input) {
- var output = "";
- var chr1, chr2, chr3;
- var enc1, enc2, enc3, enc4;
- var i = 0;
-
- input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
-
- while (i < input.length) {
-
- enc1 = this._keyStr.indexOf(input.charAt(i++));
- enc2 = this._keyStr.indexOf(input.charAt(i++));
- enc3 = this._keyStr.indexOf(input.charAt(i++));
- enc4 = this._keyStr.indexOf(input.charAt(i++));
-
- chr1 = (enc1 << 2) | (enc2 >> 4);
- chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
- chr3 = ((enc3 & 3) << 6) | enc4;
-
- output = output + String.fromCharCode(chr1);
-
- if (enc3 != 64) {
- output = output + String.fromCharCode(chr2);
- }
- if (enc4 != 64) {
- output = output + String.fromCharCode(chr3);
- }
-
- }
-
- output = this._utf8_decode(output);
-
- return output;
-
- },
-
- // private method for UTF-8 encoding
- _utf8_encode : function (string) {
- string = string.replace(/\r\n/g,"\n");
- var utftext = "";
-
- for (var n = 0; n < string.length; n++) {
-
- var c = string.charCodeAt(n);
-
- if (c < 128) {
- utftext += String.fromCharCode(c);
- }
- else if((c > 127) && (c < 2048)) {
- utftext += String.fromCharCode((c >> 6) | 192);
- utftext += String.fromCharCode((c & 63) | 128);
- }
- else {
- utftext += String.fromCharCode((c >> 12) | 224);
- utftext += String.fromCharCode(((c >> 6) & 63) | 128);
- utftext += String.fromCharCode((c & 63) | 128);
- }
-
- }
-
- return utftext;
- },
-
- // private method for UTF-8 decoding
- _utf8_decode : function (utftext) {
- var string = "";
- var i = 0;
- var c = c1 = c2 = 0;
-
- while ( i < utftext.length ) {
-
- c = utftext.charCodeAt(i);
-
- if (c < 128) {
- string += String.fromCharCode(c);
- i++;
- }
- else if((c > 191) && (c < 224)) {
- c2 = utftext.charCodeAt(i+1);
- string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
- i += 2;
- }
- else {
- c2 = utftext.charCodeAt(i+1);
- c3 = utftext.charCodeAt(i+2);
- string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
- i += 3;
- }
-
- }
-
- return string;
- }
- }
-\ No newline at end of file
+}
+\ No newline at end of file
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -0,0 +1,244 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright © 2009 Center for History and New Media
+ George Mason University, Fairfax, Virginia, USA
+ http://zotero.org
+
+ This file is part of Zotero.
+
+ Zotero is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Zotero is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Zotero. If not, see <http://www.gnu.org/licenses/>.
+
+
+ Utilities based in part on code taken from Piggy Bank 2.1.1 (BSD-licensed)
+
+ ***** END LICENSE BLOCK *****
+*/
+
+/**
+ * @class Utility functions not made available to translators
+ */
+Zotero.Utilities.Internal = {
+ /*
+ * Adapted from http://developer.mozilla.org/en/docs/nsICryptoHash
+ *
+ * @param {String|nsIFile} strOrFile
+ * @param {Boolean} [base64=false] Return as base-64-encoded string rather than hex string
+ * @return {String}
+ */
+ "md5":function(strOrFile, base64) {
+ if (typeof strOrFile == 'string') {
+ var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
+ createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
+ converter.charset = "UTF-8";
+ var result = {};
+ var data = converter.convertToByteArray(strOrFile, result);
+ var ch = Components.classes["@mozilla.org/security/hash;1"]
+ .createInstance(Components.interfaces.nsICryptoHash);
+ ch.init(ch.MD5);
+ ch.update(data, data.length);
+ }
+ else if (strOrFile instanceof Components.interfaces.nsIFile) {
+ // Otherwise throws (NS_ERROR_NOT_AVAILABLE) [nsICryptoHash.updateFromStream]
+ if (!strOrFile.fileSize) {
+ // MD5 for empty string
+ return "d41d8cd98f00b204e9800998ecf8427e";
+ }
+
+ var istream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+ .createInstance(Components.interfaces.nsIFileInputStream);
+ // open for reading
+ istream.init(strOrFile, 0x01, 0444, 0);
+ var ch = Components.classes["@mozilla.org/security/hash;1"]
+ .createInstance(Components.interfaces.nsICryptoHash);
+ // we want to use the MD5 algorithm
+ ch.init(ch.MD5);
+ // this tells updateFromStream to read the entire file
+ const PR_UINT32_MAX = 0xffffffff;
+ ch.updateFromStream(istream, PR_UINT32_MAX);
+ }
+
+ // pass false here to get binary data back
+ var hash = ch.finish(base64);
+
+ if (istream) {
+ istream.close();
+ }
+
+ if (base64) {
+ return hash;
+ }
+
+ /*
+ // This created 36-character hashes
+
+ // return the two-digit hexadecimal code for a byte
+ function toHexString(charCode) {
+ return ("0" + charCode.toString(16)).slice(-2);
+ }
+
+ // convert the binary hash data to a hex string.
+ return [toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
+ */
+
+ // From http://rcrowley.org/2007/11/15/md5-in-xulrunner-or-firefox-extensions/
+ var ascii = [];
+ var ii = hash.length;
+ for (var i = 0; i < ii; ++i) {
+ var c = hash.charCodeAt(i);
+ var ones = c % 16;
+ var tens = c >> 4;
+ ascii.push(String.fromCharCode(tens + (tens > 9 ? 87 : 48)) + String.fromCharCode(ones + (ones > 9 ? 87 : 48)));
+ }
+ return ascii.join('');
+ }
+}
+
+/**
+ * Base64 encode / decode
+ * From http://www.webtoolkit.info/
+ */
+Zotero.Utilities.Internal.Base64 = {
+ // private property
+ _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+ // public method for encoding
+ encode : function (input) {
+ var output = "";
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+ var i = 0;
+
+ input = this._utf8_encode(input);
+
+ while (i < input.length) {
+
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+
+ output = output +
+ this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
+ this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
+
+ }
+
+ return output;
+ },
+
+ // public method for decoding
+ decode : function (input) {
+ var output = "";
+ var chr1, chr2, chr3;
+ var enc1, enc2, enc3, enc4;
+ var i = 0;
+
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+ while (i < input.length) {
+
+ enc1 = this._keyStr.indexOf(input.charAt(i++));
+ enc2 = this._keyStr.indexOf(input.charAt(i++));
+ enc3 = this._keyStr.indexOf(input.charAt(i++));
+ enc4 = this._keyStr.indexOf(input.charAt(i++));
+
+ chr1 = (enc1 << 2) | (enc2 >> 4);
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+ chr3 = ((enc3 & 3) << 6) | enc4;
+
+ output = output + String.fromCharCode(chr1);
+
+ if (enc3 != 64) {
+ output = output + String.fromCharCode(chr2);
+ }
+ if (enc4 != 64) {
+ output = output + String.fromCharCode(chr3);
+ }
+
+ }
+
+ output = this._utf8_decode(output);
+
+ return output;
+
+ },
+
+ // private method for UTF-8 encoding
+ _utf8_encode : function (string) {
+ string = string.replace(/\r\n/g,"\n");
+ var utftext = "";
+
+ for (var n = 0; n < string.length; n++) {
+
+ var c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ },
+
+ // private method for UTF-8 decoding
+ _utf8_decode : function (utftext) {
+ var string = "";
+ var i = 0;
+ var c = c1 = c2 = 0;
+
+ while ( i < utftext.length ) {
+
+ c = utftext.charCodeAt(i);
+
+ if (c < 128) {
+ string += String.fromCharCode(c);
+ i++;
+ }
+ else if((c > 191) && (c < 224)) {
+ c2 = utftext.charCodeAt(i+1);
+ string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
+ i += 2;
+ }
+ else {
+ c2 = utftext.charCodeAt(i+1);
+ c3 = utftext.charCodeAt(i+2);
+ string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ i += 3;
+ }
+
+ }
+
+ return string;
+ }
+ }
+\ No newline at end of file
diff --git a/chrome/content/zotero/xpcom/utilities_translate.js b/chrome/content/zotero/xpcom/utilities_translate.js
@@ -0,0 +1,442 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright © 2009 Center for History and New Media
+ George Mason University, Fairfax, Virginia, USA
+ http://zotero.org
+
+ This file is part of Zotero.
+
+ Zotero is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Zotero is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Zotero. If not, see <http://www.gnu.org/licenses/>.
+
+
+ Utilities based in part on code taken from Piggy Bank 2.1.1 (BSD-licensed)
+
+ ***** END LICENSE BLOCK *****
+*/
+
+/**
+ * @class All functions accessible from within Zotero.Utilities namespace inside sandboxed
+ * translators
+ *
+ * @constructor
+ * @augments Zotero.Utilities
+ * @borrows Zotero.Date.formatDate as this.formatDate
+ * @borrows Zotero.Date.strToDate as this.strToDate
+ * @borrows Zotero.Date.strToISO as this.strToISO
+ * @borrows Zotero.OpenURL.createContextObject as this.createContextObject
+ * @borrows Zotero.OpenURL.parseContextObject as this.parseContextObject
+ * @borrows Zotero.HTTP.processDocuments as this.processDocuments
+ * @borrows Zotero.HTTP.doPost as this.doPost
+ * @param {Zotero.Translate} translate
+ */
+Zotero.Utilities.Translate = function(translate) {
+ this._translate = translate;
+}
+
+var tmp = function() {};
+tmp.prototype = Zotero.Utilities;
+Zotero.Utilities.Translate.prototype = new tmp();
+
+Zotero.Utilities.Translate.prototype.formatDate = Zotero.Date.formatDate;
+Zotero.Utilities.Translate.prototype.strToDate = Zotero.Date.strToDate;
+Zotero.Utilities.Translate.prototype.strToISO = Zotero.Date.strToISO;
+Zotero.Utilities.Translate.prototype.createContextObject = Zotero.OpenURL.createContextObject;
+Zotero.Utilities.Translate.prototype.parseContextObject = Zotero.OpenURL.parseContextObject;
+
+/**
+ * Hack to overloads {@link Zotero.Utilities.capitalizeTitle} to allow overriding capitalizeTitles
+ * pref on a per-translate instance basis (for translator testing only)
+ */
+Zotero.Utilities.Translate.prototype.capitalizeTitle = function(string, force) {
+ if(force === undefined) {
+ var translate = this._translate;
+ do {
+ if(translate.capitalizeTitles !== undefined) {
+ force = translate.capitalizeTitles;
+ break;
+ }
+ } while(translate = translate._parentTranslator);
+ }
+
+ return Zotero.Utilities.capitalizeTitle(string, force);
+}
+
+/**
+ * Gets the current Zotero version
+ *
+ * @type String
+ */
+Zotero.Utilities.Translate.prototype.getVersion = function() {
+ return Zotero.version;
+}
+
+/**
+ * Takes an XPath query and returns the results
+ *
+ * @deprecated Use {@link Zotero.Utilities.xpath} or doc.evaluate() directly
+ * @type Node[]
+ */
+Zotero.Utilities.Translate.prototype.gatherElementsOnXPath = function(doc, parentNode, xpath, nsResolver) {
+ var elmts = [];
+
+ var iterator = doc.evaluate(xpath, parentNode, nsResolver,
+ (Zotero.isFx ? Components.interfaces.nsIDOMXPathResult.ANY_TYPE : XPathResult.ANY_TYPE),
+ null);
+ var elmt = iterator.iterateNext();
+ var i = 0;
+ while (elmt) {
+ elmts[i++] = elmt;
+ elmt = iterator.iterateNext();
+ }
+ return elmts;
+}
+
+/**
+ * Gets a given node as a string containing all child nodes
+ *
+ * @deprecated Use doc.evaluate and the "nodeValue" or "textContent" property
+ * @type String
+ */
+Zotero.Utilities.Translate.prototype.getNodeString = function(doc, contextNode, xpath, nsResolver) {
+ var elmts = this.gatherElementsOnXPath(doc, contextNode, xpath, nsResolver);
+ var returnVar = "";
+ for(var i=0; i<elmts.length; i++) {
+ returnVar += elmts[i].nodeValue;
+ }
+ return returnVar;
+}
+
+/**
+ * Grabs items based on URLs
+ *
+ * @param {Document} doc DOM document object
+ * @param {Element|Element[]} inHere DOM element(s) to process
+ * @param {RegExp} [urlRe] Regexp of URLs to add to list
+ * @param {RegExp} [urlRe] Regexp of URLs to reject
+ * @return {Object} Associative array of link => textContent pairs, suitable for passing to
+ * Zotero.selectItems from within a translator
+ */
+Zotero.Utilities.Translate.prototype.getItemArray = function(doc, inHere, urlRe, rejectRe) {
+ var availableItems = new Object(); // Technically, associative arrays are objects
+
+ // Require link to match this
+ if(urlRe) {
+ if(urlRe.exec) {
+ var urlRegexp = urlRe;
+ } else {
+ var urlRegexp = new RegExp();
+ urlRegexp.compile(urlRe, "i");
+ }
+ }
+ // Do not allow text to match this
+ if(rejectRe) {
+ if(rejectRe.exec) {
+ var rejectRegexp = rejectRe;
+ } else {
+ var rejectRegexp = new RegExp();
+ rejectRegexp.compile(rejectRe, "i");
+ }
+ }
+
+ if(!inHere.length) {
+ inHere = new Array(inHere);
+ }
+
+ for(var j=0; j<inHere.length; j++) {
+ var links = inHere[j].getElementsByTagName("a");
+ for(var i=0; i<links.length; i++) {
+ if(!urlRe || urlRegexp.test(links[i].href)) {
+ var text = links[i].textContent;
+ if(text) {
+ text = this.trimInternal(text);
+ if(!rejectRe || !rejectRegexp.test(text)) {
+ if(availableItems[links[i].href]) {
+ if(text != availableItems[links[i].href]) {
+ availableItems[links[i].href] += " "+text;
+ }
+ } else {
+ availableItems[links[i].href] = text;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return availableItems;
+}
+
+
+/**
+ * Load a single document in a hidden browser
+ *
+ * @deprecated Use processDocuments with a single URL
+ * @see Zotero.Utilities.Translate#processDocuments
+ */
+Zotero.Utilities.Translate.prototype.loadDocument = function(url, succeeded, failed) {
+ Zotero.debug("Zotero.Utilities.loadDocument is deprecated; please use processDocuments in new code");
+ this.processDocuments([url], succeeded, null, failed);
+}
+
+/**
+ * Already documented in Zotero.HTTP
+ * @ignore
+ */
+Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor, done, exception) {
+ if(typeof(urls) == "string") {
+ urls = [this._convertURL(urls)];
+ } else {
+ for(var i in urls) {
+ urls[i] = this._convertURL(urls[i]);
+ }
+ }
+
+ // Unless the translator has proposed some way to handle an error, handle it
+ // by throwing a "scraping error" message
+ var translate = this._translate;
+ if(exception) {
+ var myException = function(e) {
+ try {
+ exception(e);
+ } catch(e) {
+ try {
+ Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
+ } catch(e) {}
+ translate.complete(false, e);
+ }
+ }
+ } else {
+ var myException = function(e) {
+ try {
+ Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
+ } catch(e) {}
+ translate.complete(false, e);
+ }
+ }
+
+ var translate = this._translate;
+ translate.incrementAsyncProcesses();
+ var hiddenBrowser = Zotero.HTTP.processDocuments(urls, processor, function() {
+ if(done) done();
+ translate.decrementAsyncProcesses();
+ translate.setHandler("done", function() {
+ try {
+ Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
+ } catch(e) {}
+ });
+ }, myException, true, translate.cookieSandbox);
+}
+
+/**
+ * Gets the DOM document object corresponding to the page located at URL, but avoids locking the
+ * UI while the request is in process.
+ *
+ * @param {String} url URL to load
+ * @return {Document} DOM document object
+ */
+Zotero.Utilities.Translate.prototype.retrieveDocument = function(url) {
+ if(!Zotero.isFx) throw "Zotero.Utilities.retrieveDocument() is unsupported outside of Firefox";
+ this._translate._debug("WARNING: Zotero.Utilities.retrieveDocument() is unsupported outside of Firefox", 1);
+
+ url = this._convertURL(url);
+
+ var mainThread = Zotero.mainThread;
+ var loaded = false;
+ var listener = function() {
+ loaded = hiddenBrowser.contentDocument.location.href != "about:blank";
+ }
+
+ var hiddenBrowser = Zotero.Browser.createHiddenBrowser();
+ if(translate.cookieSandbox) translate.cookieSandbox.attachToBrowser(hiddenBrowser);
+
+ hiddenBrowser.addEventListener("pageshow", listener, true);
+ hiddenBrowser.loadURI(url);
+
+ // Use a timeout of 2 minutes. Without a timeout, a request to an IP at which no system is
+ // configured will continue indefinitely, and hang Firefox as it shuts down. No same request
+ // should ever take longer than 2 minutes.
+ var endTime = Date.now() + 120000;
+ while(!loaded && Date.now() < endTime) {
+ mainThread.processNextEvent(true);
+ }
+
+ hiddenBrowser.removeEventListener("pageshow", listener, true);
+ hiddenBrowser.contentWindow.setTimeout(function() {
+ Zotero.Browser.deleteHiddenBrowser(hiddenBrowser);
+ }, 1);
+
+ if(!loaded) throw "retrieveDocument failed: request timeout";
+ return hiddenBrowser.contentDocument;
+}
+
+/**
+ * Gets the source of the page located at URL, but avoids locking the UI while the request is in
+ * process.
+ *
+ * @param {String} url URL to load
+ * @param {String} [body=null] Request body to POST to the URL; a GET request is
+ * executed if no body is present
+ * @param {Object} [headers] HTTP headers to include in request;
+ * Content-Type defaults to application/x-www-form-urlencoded
+ * for POST; ignored if no body
+ * @param {String} [responseCharset] Character set to force on the response
+ * @return {String} Request body
+ */
+Zotero.Utilities.Translate.prototype.retrieveSource = function(url, body, headers, responseCharset) {
+ this._translate._debug("WARNING: Use of Zotero.Utilities.retrieveSource() is deprecated. "+
+ "The main thread will be frozen when Zotero.Utilities.retrieveSource() is called outside "+
+ "of Firefox, and cross-domain requests will not work.", 1);
+
+ if(Zotero.isFx) {
+ /* Apparently, a synchronous XMLHttpRequest would have the behavior of this routine in FF3, but
+ * in FF3.5, synchronous XHR blocks all JavaScript on the thread. See
+ * http://hacks.mozilla.org/2009/07/synchronous-xhr/. */
+ url = this._convertURL(url);
+ if(!headers) headers = null;
+ if(!responseCharset) responseCharset = null;
+
+ var mainThread = Zotero.mainThread;
+ var finished = false;
+ var listener = function() { finished = true };
+
+ if(body) {
+ var xmlhttp = Zotero.HTTP.doPost(url, body, listener, headers, responseCharset, translate.cookieSandbox);
+ } else {
+ var xmlhttp = Zotero.HTTP.doGet(url, listener, responseCharset, translate.cookieSandbox);
+ }
+
+ while(!finished) mainThread.processNextEvent(true);
+ } else {
+ // Use a synchronous XMLHttpRequest, even though this is inadvisable
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open((body ? "POST" : "GET"), url, false);
+ xmlhttp.send(body ? body : null);
+ }
+
+ if(xmlhttp.status >= 400) throw "Zotero.Utilities.retrieveSource() failed: "+xmlhttp.status+" "+xmlhttp.statusText;
+
+ return xmlhttp.responseText;
+}
+
+/**
+* Send an HTTP GET request via XMLHTTPRequest
+*
+* @param {String|String[]} urls URL(s) to request
+* @param {Function} processor Callback to be executed for each document loaded
+* @param {Function} done Callback to be executed after all documents have been loaded
+* @param {String} responseCharset Character set to force on the response
+* @return {Boolean} True if the request was sent, or false if the browser is offline
+*/
+Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, responseCharset) {
+ var callAgain = false;
+
+ if(typeof(urls) == "string") {
+ var url = urls;
+ } else {
+ if(urls.length > 1) callAgain = true;
+ var url = urls.shift();
+ }
+
+ url = this._convertURL(url);
+
+ var me = this;
+
+ this._translate.incrementAsyncProcesses();
+ var xmlhttp = Zotero.HTTP.doGet(url, function(xmlhttp) {
+ try {
+ if(processor) {
+ processor(xmlhttp.responseText, xmlhttp, url);
+ }
+
+ if(callAgain) {
+ me.doGet(urls, processor, done);
+ } else {
+ if(done) {
+ done();
+ }
+ }
+ me._translate.decrementAsyncProcesses();
+ } catch(e) {
+ me._translate.complete(false, e);
+ }
+ }, responseCharset, this._translate.cookieSandbox);
+}
+
+/**
+ * Already documented in Zotero.HTTP
+ * @ignore
+ */
+Zotero.Utilities.Translate.prototype.doPost = function(url, body, onDone, headers, responseCharset) {
+ url = this._convertURL(url);
+
+ var translate = this._translate;
+ this._translate.incrementAsyncProcesses();
+ var xmlhttp = Zotero.HTTP.doPost(url, body, function(xmlhttp) {
+ try {
+ onDone(xmlhttp.responseText, xmlhttp);
+ translate.decrementAsyncProcesses();
+ } catch(e) {
+ translate.complete(false, e);
+ }
+ }, headers, responseCharset, translate.cookieSandbox ? translate.cookieSandbox : undefined);
+}
+
+/**
+ * Translate a URL to a form that goes through the appropriate proxy, or convert a relative URL to
+ * an absolute one
+ *
+ * @param {String} url
+ * @type String
+ * @private
+ */
+Zotero.Utilities.Translate.prototype._convertURL = function(url) {
+ const protocolRe = /^(?:(?:http|https|ftp):)/i;
+
+ // convert proxy to proper if applicable
+ if(protocolRe.test(url)) {
+ if(this._translate.translator && this._translate.translator[0]
+ && this._translate.translator[0].properToProxy) {
+ url = this._translate.translator[0].properToProxy(url);
+ }
+ return url;
+ }
+
+ // resolve local URL
+ var resolved = "";
+ if(Zotero.isFx) {
+ resolved = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService).
+ newURI(this._translate.location, "", null).resolve(url);
+ } else if(Zotero.isNode) {
+ resolved = require('url').resolve(this._translate.location, url);
+ } else {
+ var a = document.createElement('a');
+ a.href = url;
+ resolved = a.href;
+ }
+
+ if(!protocolRe.test(resolved)) {
+ throw new Error("Invalid URL supplied for HTTP request: "+url);
+ }
+
+ return resolved;
+}
+
+Zotero.Utilities.Translate.prototype.__exposedProps__ = {"HTTP":"r"};
+for(var j in Zotero.Utilities.Translate.prototype) {
+ if(typeof Zotero.Utilities.Translate.prototype[j] === "function" && j[0] !== "_" && j != "Translate") {
+ Zotero.Utilities.Translate.prototype.__exposedProps__[j] = "r";
+ }
+}
+\ No newline at end of file
diff --git a/chrome/skin/default/zotero/timeline/bundle.js b/chrome/skin/default/zotero/timeline/bundle.js
@@ -233,7 +233,7 @@ Timeline.GregorianDateLabeller=function(locale,timeZone){this._locale=locale;thi
Modified by Ben for Zotero
*/
-Timeline.GregorianDateLabeller.monthNames = Zotero.Date.months.short;
+Timeline.GregorianDateLabeller.monthNames = Zotero.Date.getMonths().short;
Timeline.GregorianDateLabeller.getMonthName=function(month,locale) {
return Timeline.GregorianDateLabeller.monthNames[month];
};
diff --git a/components/zotero-service.js b/components/zotero-service.js
@@ -45,7 +45,9 @@ const xpcomFilesAll = [
'translation/translate',
'translation/translate_firefox',
'translation/tlds',
- 'utilities'
+ 'utilities',
+ 'utilities_internal',
+ 'utilities_translate'
];
/** XPCOM files to be loaded only for local translation and DB access **/