- Overhaul of Zotero.Translate instance. New code should use new Zotero.Translate.Web, Zotero.Translate.Import, etc. The core Translate class is now abstracted away from data access, read/write IO, and the sandbox API. This all needs more testing.
- Translators now use configOptions and displayOptions properties in their metadata instead of Zotero.configure() and Zotero.addOption() to specify interfaces. - Replaced now broken Zotero.Utilities.inArray() appearances in MODS.js with proper indexOf() calls
This commit is contained in:
parent
42a1551e85
commit
3f2a8a39ab
20 changed files with 3408 additions and 3268 deletions
File diff suppressed because it is too large
Load diff
410
chrome/content/zotero/xpcom/translation/browser_firefox.js
Normal file
410
chrome/content/zotero/xpcom/translation/browser_firefox.js
Normal file
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
***** 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
const BOMs = {
|
||||
"UTF-8":"\xEF\xBB\xBF",
|
||||
"UTF-16BE":"\xFE\xFF",
|
||||
"UTF-16LE":"\xFF\xFE",
|
||||
"UTF-32BE":"\x00\x00\xFE\xFF",
|
||||
"UTF-32LE":"\xFF\xFE\x00\x00"
|
||||
}
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
/**
|
||||
* @class Manages the translator sandbox
|
||||
* @param {Zotero.Translate} translate
|
||||
* @param {String|window} sandboxLocation
|
||||
*/
|
||||
Zotero.Translate.SandboxManager = function(translate, sandboxLocation) {
|
||||
this.sandbox = new Components.utils.Sandbox(sandboxLocation);
|
||||
this.sandbox.Zotero = {};
|
||||
this._translate = translate;
|
||||
|
||||
// import functions missing from global scope into Fx sandbox
|
||||
this.sandbox.XPathResult = Components.interfaces.nsIDOMXPathResult;
|
||||
}
|
||||
|
||||
Zotero.Translate.SandboxManager.prototype = {
|
||||
/**
|
||||
* Evaluates code in the sandbox
|
||||
*/
|
||||
"eval":function(code) {
|
||||
Components.utils.evalInSandbox(code, this.sandbox);
|
||||
},
|
||||
|
||||
/**
|
||||
* Imports an object into the sandbox
|
||||
*
|
||||
* @param {Object} object Object to be imported (under Zotero)
|
||||
* @param {Boolean} passTranslateAsFirstArgument Whether the translate instance should be passed
|
||||
* as the first argument to the function.
|
||||
*/
|
||||
"importObject":function(object, passAsFirstArgument, attachTo) {
|
||||
if(!attachTo) attachTo = this.sandbox.Zotero;
|
||||
for(var key in (object.__exposedProps__ ? object.__exposedProps__ : object)) {
|
||||
let localKey;
|
||||
if(object.__exposedProps__) {
|
||||
localKey = object.__exposedProps__[key];
|
||||
} else {
|
||||
localKey = key;
|
||||
}
|
||||
|
||||
// magical XPCSafeJSObjectWrappers for sandbox
|
||||
if(typeof object[localKey] === "function" || typeof object[localKey] === "object") {
|
||||
attachTo[localKey] = function() {
|
||||
var args = (passAsFirstArgument ? [passAsFirstArgument] : []);
|
||||
for(var i=0; i<arguments.length; i++) {
|
||||
args.push(typeof arguments[i] === "object" || typeof arguments[i] === "function" ? new XPCSafeJSObjectWrapper(arguments[i]) : arguments[i]);
|
||||
}
|
||||
|
||||
return object[localKey].apply(object, args);
|
||||
};
|
||||
|
||||
// attach members
|
||||
if(!(object instanceof Components.interfaces.nsISupports)) {
|
||||
this.importObject(object[localKey], passAsFirstArgument ? passAsFirstArgument : null, attachTo[localKey]);
|
||||
}
|
||||
} else {
|
||||
object[localKey] = object[localKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******* (Native) Read support *******/
|
||||
|
||||
Zotero.Translate.IO.Read = function(file, mode) {
|
||||
this.file = file;
|
||||
|
||||
// open file
|
||||
this._rawStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
this._rawStream.init(file, 0x01, 0664, 0);
|
||||
|
||||
// start detecting charset
|
||||
var charset = null;
|
||||
|
||||
// look for a BOM in the document
|
||||
if(Zotero.isFx4) {
|
||||
var first4 = NetUtil.readInputStreamToString(this._rawStream, 4);
|
||||
} else {
|
||||
var binStream = Components.classes["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||
binStream.setInputStream(this._rawStream);
|
||||
var first4 = binStream.readByteArray(4);
|
||||
first4 = String.fromCharCode.apply(null, first4);
|
||||
}
|
||||
|
||||
for(var possibleCharset in BOMs) {
|
||||
if(first4.substr(0, BOMs[possibleCharset].length) == BOMs[possibleCharset]) {
|
||||
this._charset = possibleCharset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(this._charset) {
|
||||
// BOM found; store its length and go back to the beginning of the file
|
||||
this._bomLength = BOMs[this._charset].length;
|
||||
this._seekToStart();
|
||||
} else {
|
||||
// look for an XML parse instruction
|
||||
this._bomLength = 0;
|
||||
|
||||
var sStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
sStream.init(this._rawStream);
|
||||
|
||||
// read until we see if the file begins with a parse instruction
|
||||
const whitespaceRe = /\s/g;
|
||||
var read;
|
||||
do {
|
||||
read = sStream.read(1);
|
||||
} while(whitespaceRe.test(read))
|
||||
|
||||
if(read == "<") {
|
||||
var firstPart = read + sStream.read(4);
|
||||
if(firstPart == "<?xml") {
|
||||
// got a parse instruction, read until it ends
|
||||
read = true;
|
||||
while((read !== false) && (read !== ">")) {
|
||||
read = sStream.read(1);
|
||||
firstPart += read;
|
||||
}
|
||||
|
||||
const encodingRe = /encoding=['"]([^'"]+)['"]/;
|
||||
var m = encodingRe.exec(firstPart);
|
||||
if(m) {
|
||||
try {
|
||||
var charconv = Components.classes["@mozilla.org/charset-converter-manager;1"]
|
||||
.getService(Components.interfaces.nsICharsetConverterManager)
|
||||
.getCharsetTitle(m[1]);
|
||||
if(charconv) this._charset = m[1];
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// if we know for certain document is XML, we also know for certain that the
|
||||
// default charset for XML is UTF-8
|
||||
if(!this._charset) this._charset = "UTF-8";
|
||||
}
|
||||
}
|
||||
|
||||
// If we managed to get a charset here, then translators shouldn't be able to override it,
|
||||
// since it's almost certainly correct. Otherwise, we allow override.
|
||||
this._allowCharsetOverride = !!this._charset;
|
||||
this._seekToStart();
|
||||
|
||||
if(!this._charset) {
|
||||
// No XML parse instruction or BOM.
|
||||
|
||||
// Check whether the user has specified a charset preference
|
||||
var charsetPref = Zotero.Prefs.get("import.charset");
|
||||
if(charsetPref == "auto") {
|
||||
// For auto-detect, we are basically going to check if the file could be valid
|
||||
// UTF-8, and if this is true, we will treat it as UTF-8. Prior likelihood of
|
||||
// UTF-8 is very high, so this should be a reasonable strategy.
|
||||
|
||||
// from http://codex.wordpress.org/User:Hakre/UTF8
|
||||
const UTF8Regex = new RegExp('^(?:' +
|
||||
'[\x09\x0A\x0D\x20-\x7E]' + // ASCII
|
||||
'|[\xC2-\xDF][\x80-\xBF]' + // non-overlong 2-byte
|
||||
'|\xE0[\xA0-\xBF][\x80-\xBF]' + // excluding overlongs
|
||||
'|[\xE1-\xEC\xEE][\x80-\xBF]{2}' + // 3-byte, but exclude U-FFFE and U-FFFF
|
||||
'|\xEF[\x80-\xBE][\x80-\xBF]' +
|
||||
'|\xEF\xBF[\x80-\xBD]' +
|
||||
'|\xED[\x80-\x9F][\x80-\xBF]' + // excluding surrogates
|
||||
'|\xF0[\x90-\xBF][\x80-\xBF]{2}' + // planes 1-3
|
||||
'|[\xF1-\xF3][\x80-\xBF]{3}' + // planes 4-15
|
||||
'|\xF4[\x80-\x8F][\x80-\xBF]{2}' + // plane 16
|
||||
')*$');
|
||||
|
||||
// Read all currently available bytes from file. I'm not sure how many this is
|
||||
// but it's a safe bet that we don't want to try to read any more than this, since
|
||||
// it would slow things down considerably.
|
||||
if(Zotero.isFx4) {
|
||||
var fileContents = NetUtil.readInputStreamToString(this._rawStream, this._rawStream.available());
|
||||
} else {
|
||||
var fileContents = binStream.readByteArray(this._rawStream.available());
|
||||
fileContents = String.fromCharCode.apply(null, fileContents);
|
||||
}
|
||||
|
||||
// Seek back to beginning of file
|
||||
this._seekToStart();
|
||||
|
||||
// See whether this could be UTF-8
|
||||
if(UTF8Regex.test(fileContents)) {
|
||||
// Assume this is UTF-8
|
||||
this._charset = "UTF-8";
|
||||
} else {
|
||||
// Can't be UTF-8; see if a default charset is defined
|
||||
this._charset = Zotero.Prefs.get("intl.charset.default", true);
|
||||
|
||||
// ISO-8859-1 by default
|
||||
if(!this._charset) this._charset = "ISO-8859-1";
|
||||
}
|
||||
} else {
|
||||
// No need to auto-detect; user has specified a charset
|
||||
this._charset = charsetPref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.debug("Translate: Detected file charset as "+this._charset);
|
||||
|
||||
// We know the charset now. Open a converter stream.
|
||||
if(mode) this.reset(mode);
|
||||
}
|
||||
|
||||
Zotero.Translate.IO.Read.prototype = {
|
||||
"__exposedProps__":["getXML", "RDF", "read", "setCharacterSet"],
|
||||
|
||||
"_seekToStart":function() {
|
||||
this._rawStream.QueryInterface(Components.interfaces.nsISeekableStream)
|
||||
.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, this._bomLength);
|
||||
},
|
||||
|
||||
"_readToString":function() {
|
||||
var str = {};
|
||||
this.inputStream.readString(this.file.fileSize, str);
|
||||
return str.value;
|
||||
},
|
||||
|
||||
"_initRDF":function() {
|
||||
// get URI
|
||||
var IOService = Components.classes['@mozilla.org/network/io-service;1']
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
var fileHandler = IOService.getProtocolHandler("file")
|
||||
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
||||
var baseURI = fileHandler.getURLSpecFromFile(this.file);
|
||||
|
||||
Zotero.debug("Translate: Initializing RDF data store");
|
||||
this._dataStore = new Zotero.RDF.AJAW.RDFIndexedFormula();
|
||||
var parser = new Zotero.RDF.AJAW.RDFParser(this._dataStore);
|
||||
var nodes = Zotero.Translate.IO.parseDOMXML(this._rawStream, this._charset, this.file.fileSize);
|
||||
parser.parse(nodes, baseURI);
|
||||
|
||||
this.RDF = new Zotero.Translate.IO._RDFSandbox(this._dataStore);
|
||||
},
|
||||
|
||||
"setCharacterSet":function(charset) {
|
||||
if(typeof charset !== "string") {
|
||||
throw "Translate: setCharacterSet: charset must be a string";
|
||||
}
|
||||
|
||||
// seek back to the beginning
|
||||
this._seekToStart();
|
||||
|
||||
if(this._allowCharsetOverride) {
|
||||
this.inputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
try {
|
||||
this.inputStream.init(this._rawStream, charset, 65535,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
} catch(e) {
|
||||
throw "Translate: setCharacterSet: text encoding not supported";
|
||||
}
|
||||
} else {
|
||||
Zotero.debug("Translate: setCharacterSet: translate charset override ignored due to BOM or XML parse instruction");
|
||||
}
|
||||
},
|
||||
|
||||
"read":function(bytes) {
|
||||
var str = {};
|
||||
|
||||
if(bytes) {
|
||||
// read number of bytes requested
|
||||
var amountRead = this.inputStream.readString(bytes, str);
|
||||
} else {
|
||||
// bytes not specified; read a line
|
||||
this.inputStream.QueryInterface(Components.interfaces.nsIUnicharLineInputStream);
|
||||
var amountRead = this.inputStream.readLine(str);
|
||||
}
|
||||
|
||||
if(amountRead) {
|
||||
return str.value;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
"getXML":function() {
|
||||
if(this._mode == "xml/dom") {
|
||||
return Zotero.Translate.IO.parseDOMXML(this._rawStream, this._charset, this.file.fileSize);
|
||||
} else {
|
||||
return new XML(this._readToString().replace(/<\?xml[^>]+\?>/, ""));
|
||||
}
|
||||
},
|
||||
|
||||
"reset":function(newMode) {
|
||||
this._seekToStart();
|
||||
this.inputStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
this.inputStream.init(this._rawStream, this._charset, 65535,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
|
||||
this._mode = newMode;
|
||||
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1 && !this.RDF) {
|
||||
this._initRDF();
|
||||
}
|
||||
},
|
||||
|
||||
"close":function() {
|
||||
this.inputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/******* Write support *******/
|
||||
|
||||
Zotero.Translate.IO.Write = function(file, mode, charset) {
|
||||
this._rawStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
this._rawStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
|
||||
this._writtenToStream = false;
|
||||
if(mode) this.reset(mode, charset);
|
||||
}
|
||||
|
||||
Zotero.Translate.IO.Write.prototype = {
|
||||
"__exposedProps__":["RDF", "write", "setCharacterSet"],
|
||||
|
||||
"_initRDF":function() {
|
||||
Zotero.debug("Translate: Initializing RDF data store");
|
||||
this._dataStore = new Zotero.RDF.AJAW.RDFIndexedFormula();
|
||||
this.RDF = new Zotero.Translate.IO._RDFSandbox(this._dataStore);
|
||||
},
|
||||
|
||||
"setCharacterSet":function(charset) {
|
||||
if(typeof charset !== "string") {
|
||||
throw "Translate: setCharacterSet: charset must be a string";
|
||||
}
|
||||
|
||||
this.outputStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterOutputStream);
|
||||
if(charset == "UTF-8xBOM") charset = "UTF-8";
|
||||
this.outputStream.init(this._rawStream, charset, 1024, "?".charCodeAt(0));
|
||||
this._charset = charset;
|
||||
},
|
||||
|
||||
"write":function(data) {
|
||||
if(!this._writtenToStream && this._charset.substr(this._charset.length-4) == "xBOM"
|
||||
&& BOMs[this._charset.substr(0, this._charset.length-4).toUpperCase()]) {
|
||||
// If stream has not yet been written to, and a UTF type has been selected, write BOM
|
||||
this._rawStream.write(BOMs[streamCharset], BOMs[streamCharset].length);
|
||||
}
|
||||
|
||||
if(this._charset == "MACINTOSH") {
|
||||
// fix buggy Mozilla MacRoman
|
||||
var splitData = data.split(/([\r\n]+)/);
|
||||
for(var i=0; i<splitData.length; i+=2) {
|
||||
// write raw newlines straight to the string
|
||||
this.outputStream.writeString(splitData[i]);
|
||||
if(splitData[i+1]) {
|
||||
this._rawStream.write(splitData[i+1], splitData[i+1].length);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.outputStream.writeString(data);
|
||||
}
|
||||
|
||||
this._writtenToStream = true;
|
||||
},
|
||||
|
||||
"reset":function(newMode, charset) {
|
||||
this._mode = newMode;
|
||||
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1) {
|
||||
this._initRDF();
|
||||
if(!this._writtenToString) this.setCharacterSet("UTF-8");
|
||||
} else if(!this._writtenToString) {
|
||||
this.setCharacterSet(charset ? charset : "UTF-8");
|
||||
}
|
||||
},
|
||||
|
||||
"close":function() {
|
||||
if(Zotero.Translate.IO.rdfDataModes.indexOf(this._mode) !== -1) {
|
||||
this.write(this.RDF.serialize());
|
||||
} else {
|
||||
this.outputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
66
chrome/content/zotero/xpcom/translation/browser_other.js
Normal file
66
chrome/content/zotero/xpcom/translation/browser_other.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
***** 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class Manages the translator sandbox
|
||||
* @param {Zotero.Translate} translate
|
||||
* @param {String|window} sandboxLocation
|
||||
*/
|
||||
Zotero.Translate.SandboxManager = function(translate, sandboxLocation) {
|
||||
this.sandbox = {};
|
||||
this._translate = translate;
|
||||
}
|
||||
|
||||
Zotero.Translate.SandboxManager.prototype = {
|
||||
/**
|
||||
* Evaluates code in the sandbox
|
||||
*/
|
||||
"eval":function(code) {
|
||||
// eval in sandbox scope
|
||||
(new Function("with(this) { " + code + " }")).call(this.sandbox);
|
||||
},
|
||||
|
||||
/**
|
||||
* Imports an object into the sandbox
|
||||
*
|
||||
* @param {Object} object Object to be imported (under Zotero)
|
||||
* @param {Boolean} passTranslateAsFirstArgument Whether the translate instance should be passed
|
||||
* as the first argument to the function.
|
||||
*/
|
||||
"importObject":function(object, passAsFirstArgument) {
|
||||
var translate = this._translate;
|
||||
|
||||
for(var key in (object.__exposedProps__ ? object.__exposedProps__ : object)) {
|
||||
var fn = (function(object, key) { return object[key] })();
|
||||
|
||||
// magic "this"-preserving wrapping closure
|
||||
this.sandbox[key] = function() {
|
||||
var args = (passAsFirstArgument ? [passAsFirstArgument] : []);
|
||||
for(var i=0; i<arguments.length; i++) args.push(arguments[i]);
|
||||
fn.apply(object, args);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
30
chrome/content/zotero/xpcom/translation/item_connector.js
Normal file
30
chrome/content/zotero/xpcom/translation/item_connector.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
***** 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.Translate.Item = {
|
||||
"saveItem":function (translate, item) {
|
||||
|
||||
}
|
||||
}
|
732
chrome/content/zotero/xpcom/translation/item_local.js
Normal file
732
chrome/content/zotero/xpcom/translation/item_local.js
Normal file
|
@ -0,0 +1,732 @@
|
|||
/*
|
||||
***** 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
Zotero.Translate.ItemSaver = function(libraryID, attachmentMode, forceTagType) {
|
||||
// initialize constants
|
||||
this.newItems = [];
|
||||
this.newCollections = [];
|
||||
this._IDMap = {};
|
||||
|
||||
// determine library ID
|
||||
if(libraryID === false) {
|
||||
this._libraryID = false;
|
||||
} else if(libraryID === true || libraryID == undefined) {
|
||||
this._libraryID = null;
|
||||
} else {
|
||||
this._libraryID = libraryID;
|
||||
}
|
||||
|
||||
// determine whether to save files and attachments
|
||||
if (attachmentMode == Zotero.Translate.ItemSaver.ATTACHMENT_MODE_DOWNLOAD) {
|
||||
this._saveAttachment = this._saveAttachmentDownload;
|
||||
} else if(attachmentMode == Zotero.Translate.ItemSaver.ATTACHMENT_MODE_FILE) {
|
||||
this._saveAttachment = this._saveAttachmentFile;
|
||||
} else {
|
||||
this._saveAttachment = function() {};
|
||||
}
|
||||
|
||||
this._saveFiles = !(attachmentMode === 0);
|
||||
|
||||
// If group filesEditable==false, don't save attachments
|
||||
if (typeof this._libraryID == 'number') {
|
||||
var type = Zotero.Libraries.getType(this._libraryID);
|
||||
switch (type) {
|
||||
case 'group':
|
||||
var groupID = Zotero.Groups.getGroupIDFromLibraryID(this._libraryID);
|
||||
var group = Zotero.Groups.get(groupID);
|
||||
if (!group.filesEditable) {
|
||||
this._saveFiles = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// force tag types if requested
|
||||
this._forceTagType = forceTagType;
|
||||
};
|
||||
|
||||
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_IGNORE = 0;
|
||||
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_DOWNLOAD = 1;
|
||||
Zotero.Translate.ItemSaver.ATTACHMENT_MODE_FILE = 2;
|
||||
|
||||
Zotero.Translate.ItemSaver.prototype = {
|
||||
"saveItem":function(item) {
|
||||
// Get typeID, defaulting to "webpage"
|
||||
var type = (item.itemType ? item.itemType : "webpage");
|
||||
|
||||
if(type == "note") { // handle notes differently
|
||||
var newItem = new Zotero.Item('note');
|
||||
newItem.libraryID = this._libraryID;
|
||||
newItem.setNote(item.note);
|
||||
var myID = newItem.save();
|
||||
var newItem = Zotero.Items.get(myID);
|
||||
} else {
|
||||
if(type == "attachment") { // handle attachments differently
|
||||
var newItem = this._saveAttachment(item);
|
||||
} else {
|
||||
var typeID = Zotero.ItemTypes.getID(type);
|
||||
var newItem = new Zotero.Item(typeID);
|
||||
newItem._libraryID = this._libraryID;
|
||||
}
|
||||
|
||||
this._saveFields(item, newItem);
|
||||
|
||||
// handle creators
|
||||
if(item.creators) {
|
||||
this._saveCreators(item, newItem);
|
||||
}
|
||||
|
||||
// save item
|
||||
var myID = newItem.save();
|
||||
newItem = Zotero.Items.get(myID);
|
||||
|
||||
// handle notes
|
||||
if(item.notes) {
|
||||
this._saveNotes(item, myID);
|
||||
}
|
||||
|
||||
// handle attachments
|
||||
if(item.attachments) {
|
||||
for(var i=0; i<item.attachments.length; i++) {
|
||||
this._saveAttachment(item.attachments[i], myID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(item.itemID) this._IDMap[item.itemID] = myID;
|
||||
|
||||
// handle see also
|
||||
this._saveTags(item, newItem);
|
||||
|
||||
// add to new item list
|
||||
this.newItems.push(myID);
|
||||
|
||||
newItem = Zotero.Items.get(myID);
|
||||
return newItem;
|
||||
},
|
||||
|
||||
"saveCollection":function(collection) {
|
||||
var collectionsToProcess = [collection];
|
||||
var parentIDs = [null];
|
||||
var topLevelCollection;
|
||||
|
||||
while(collectionsToProcess) {
|
||||
var collection = collectionsToProcess.shift();
|
||||
var parentID = parentIDs.shift();
|
||||
|
||||
var newCollection = Zotero.Collections.add(collection.name, parentID);
|
||||
if(parentID === null) topLevelCollection = newCollection;
|
||||
|
||||
this.newCollections.push(newCollection.id);
|
||||
|
||||
var toAdd = [];
|
||||
|
||||
for each(child in collection.children) {
|
||||
if(child.type == "collection") {
|
||||
// do recursive processing of collections
|
||||
collectionsToProcess.push(child);
|
||||
parentIDs.push(newCollection.id);
|
||||
} else {
|
||||
// add mapped items to collection
|
||||
if(this._IDMap[child.id]) {
|
||||
toAdd.push(this._IDMap[child.id]);
|
||||
} else {
|
||||
Zotero.debug("Translate: Could not map "+child.id+" to an imported item", 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(toAdd.length) {
|
||||
Zotero.debug("Translate: Adding " + toAdd, 5);
|
||||
newCollection.addItems(toAdd);
|
||||
}
|
||||
}
|
||||
|
||||
return topLevelCollection;
|
||||
},
|
||||
|
||||
"_saveAttachmentFile":function(attachment, parentID) {
|
||||
const urlRe = /(([A-Za-z]+):\/\/[^\s]*)/i;
|
||||
Zotero.debug("Translate: Adding attachment", 4);
|
||||
|
||||
if(!attachment.url && !attachment.path) {
|
||||
Zotero.debug("Translate: Ignoring attachment: no path or URL specified", 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!attachment.path) {
|
||||
// see if this is actually a file URL
|
||||
var m = urlRe.exec(attachment.url);
|
||||
var protocol = m ? m[2].toLowerCase() : "";
|
||||
if(protocol == "file") {
|
||||
attachment.path = attachment.url;
|
||||
attachment.url = false;
|
||||
} else if(protocol != "http" && protocol != "https") {
|
||||
Zotero.debug("Translate: Unrecognized protocol "+protocol, 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!attachment.path) {
|
||||
// create from URL
|
||||
try {
|
||||
var myID = Zotero.Attachments.linkFromURL(attachment.url, parentID,
|
||||
(attachment.mimeType ? attachment.mimeType : undefined),
|
||||
(attachment.title ? attachment.title : undefined));
|
||||
} catch(e) {
|
||||
Zotero.debug("Translate: Error adding attachment "+attachment.url, 2);
|
||||
return;
|
||||
}
|
||||
Zotero.debug("Translate: Created attachment; id is "+myID, 4);
|
||||
var newItem = Zotero.Items.get(myID);
|
||||
} else {
|
||||
var uri, file;
|
||||
|
||||
// generate nsIFile
|
||||
var IOService = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
try {
|
||||
var uri = IOService.newURI(attachment.path, "", null);
|
||||
}
|
||||
catch (e) {
|
||||
var msg = "Error parsing attachment path: " + attachment.path;
|
||||
Zotero.logError(msg);
|
||||
Zotero.debug("Translate: " + msg, 2);
|
||||
}
|
||||
|
||||
if (uri) {
|
||||
try {
|
||||
var file = uri.QueryInterface(Components.interfaces.nsIFileURL).file;
|
||||
if (file.path == '/') {
|
||||
var msg = "Error parsing attachment path: " + attachment.path;
|
||||
Zotero.logError(msg);
|
||||
Zotero.debug("Translate: " + msg, 2);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
var msg = "Error getting file from attachment path: " + attachment.path;
|
||||
Zotero.logError(msg);
|
||||
Zotero.debug("Translate: " + msg, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file || !file.exists()) {
|
||||
// use attachment title if possible, or else file leaf name
|
||||
var title = attachment.title;
|
||||
if(!title) {
|
||||
title = file ? file.leafName : '';
|
||||
}
|
||||
|
||||
var myID = Zotero.Attachments.createMissingAttachment(
|
||||
attachment.url ? Zotero.Attachments.LINK_MODE_IMPORTED_URL
|
||||
: Zotero.Attachments.LINK_MODE_IMPORTED_FILE,
|
||||
file, attachment.url ? attachment.url : null, title,
|
||||
attachment.mimeType, attachment.charset, parentID);
|
||||
}
|
||||
else if (attachment.url) {
|
||||
var myID = Zotero.Attachments.importSnapshotFromFile(file,
|
||||
attachment.url, attachment.title, attachment.mimeType, attachment.charset,
|
||||
parentID);
|
||||
}
|
||||
else {
|
||||
var myID = Zotero.Attachments.importFromFile(file, parentID);
|
||||
}
|
||||
}
|
||||
|
||||
var newItem = Zotero.Items.get(myID);
|
||||
|
||||
// save fields
|
||||
this._saveFields(attachment, newItem);
|
||||
|
||||
// add note if necessary
|
||||
if(attachment.note) {
|
||||
newItem.setNote(attachment.note);
|
||||
}
|
||||
|
||||
newItem.save();
|
||||
newItem = Zotero.Items.get(myID);
|
||||
|
||||
return newItem;
|
||||
},
|
||||
|
||||
"_saveAttachmentDownload":function(attachment, parentID) {
|
||||
Zotero.debug("Translate: Adding attachment", 4);
|
||||
|
||||
// determine whether to save attachments at all
|
||||
var automaticSnapshots = Zotero.Prefs.get("automaticSnapshots");
|
||||
var downloadAssociatedFiles = Zotero.Prefs.get("downloadAssociatedFiles");
|
||||
|
||||
if(!attachment.url && !attachment.document) {
|
||||
Zotero.debug("Translate: Not adding attachment: no URL specified", 2);
|
||||
} else {
|
||||
var shouldAttach = ((attachment.document
|
||||
|| (attachment.mimeType && attachment.mimeType == "text/html")) && automaticSnapshots)
|
||||
|| downloadAssociatedFiles;
|
||||
if(!shouldAttach) return;
|
||||
|
||||
if(attachment.snapshot === false || !this._saveFiles) {
|
||||
// if snapshot is explicitly set to false, attach as link
|
||||
if(attachment.document) {
|
||||
Zotero.Attachments.linkFromURL(attachment.document.location.href, parentID,
|
||||
(attachment.mimeType ? attachment.mimeType : attachment.document.contentType),
|
||||
(attachment.title ? attachment.title : attachment.document.title));
|
||||
} else {
|
||||
if(!attachment.mimeType || !attachment.title) {
|
||||
Zotero.debug("Translate: Either mimeType or title is missing; attaching file will be slower", 3);
|
||||
}
|
||||
|
||||
try {
|
||||
Zotero.Attachments.linkFromURL(attachment.url, parentID,
|
||||
(attachment.mimeType ? attachment.mimeType : undefined),
|
||||
(attachment.title ? attachment.title : undefined));
|
||||
} catch(e) {
|
||||
Zotero.debug("Translate: Error adding attachment "+attachment.url, 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if snapshot is not explicitly set to false, retrieve snapshot
|
||||
if(attachment.document) {
|
||||
if(automaticSnapshots) {
|
||||
try {
|
||||
Zotero.Attachments.importFromDocument(attachment.document, parentID, attachment.title);
|
||||
} catch(e) {
|
||||
Zotero.debug("Translate: Error attaching document", 2);
|
||||
}
|
||||
}
|
||||
// Save attachment if snapshot pref enabled or not HTML
|
||||
// (in which case downloadAssociatedFiles applies)
|
||||
} else if(this._saveFiles && (automaticSnapshots || !attachment.mimeType
|
||||
|| attachment.mimeType != "text/html")) {
|
||||
var mimeType = null;
|
||||
var title = null;
|
||||
|
||||
if(attachment.mimeType) {
|
||||
// first, try to extract mime type from mimeType attribute
|
||||
mimeType = attachment.mimeType;
|
||||
} else if(attachment.document && attachment.document.contentType) {
|
||||
// if that fails, use document if possible
|
||||
mimeType = attachment.document.contentType
|
||||
}
|
||||
|
||||
// same procedure for title as mime type
|
||||
if(attachment.title) {
|
||||
title = attachment.title;
|
||||
} else if(attachment.document && attachment.document.title) {
|
||||
title = attachment.document.title;
|
||||
}
|
||||
|
||||
var fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(parentID);
|
||||
try {
|
||||
Zotero.Attachments.importFromURL(attachment.url, parentID, title, fileBaseName);
|
||||
} catch(e) {
|
||||
Zotero.debug("Translate: Error adding attachment "+attachment.url, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"_saveFields":function(item, newItem) {
|
||||
// fields that should be handled differently
|
||||
const skipFields = ["note", "notes", "itemID", "attachments", "tags", "seeAlso",
|
||||
"itemType", "complete", "creators"];
|
||||
|
||||
var typeID = Zotero.ItemTypes.getID(item.itemType);
|
||||
var fieldID;
|
||||
for(var field in item) {
|
||||
// loop through item fields
|
||||
if(item[field] && skipFields.indexOf(field) === -1 && (fieldID = Zotero.ItemFields.getID(field))) {
|
||||
// if field is in db and shouldn't be skipped
|
||||
|
||||
// try to map from base field
|
||||
if(Zotero.ItemFields.isBaseField(fieldID)) {
|
||||
fieldID = Zotero.ItemFields.getFieldIDFromTypeAndBase(typeID, fieldID);
|
||||
if(fieldID) {
|
||||
Zotero.debug("Translate: Mapping "+field+" to "+Zotero.ItemFields.getName(fieldID), 5);
|
||||
}
|
||||
}
|
||||
|
||||
// if field is valid for this type, set field
|
||||
Zotero.debug("Translate: Testing "+fieldID+" "+typeID);
|
||||
if(fieldID && Zotero.ItemFields.isValidForType(fieldID, typeID)) {
|
||||
newItem.setField(fieldID, item[field]);
|
||||
} else {
|
||||
Zotero.debug("Translate: Discarded field "+field+" for item: field not valid for type "+item.itemType, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"_saveCreators":function(item, newItem) {
|
||||
for(var i=0; i<item.creators.length; i++) {
|
||||
var creator = item.creators[i];
|
||||
|
||||
// try to assign correct creator type
|
||||
if(creator.creatorType) {
|
||||
try {
|
||||
var creatorTypeID = Zotero.CreatorTypes.getID(creator.creatorType);
|
||||
} catch(e) {
|
||||
Zotero.debug("Translate: Invalid creator type "+creator.creatorType+" for creator index "+j, 2);
|
||||
}
|
||||
}
|
||||
if(!creatorTypeID) {
|
||||
var creatorTypeID = 1;
|
||||
}
|
||||
|
||||
// Single-field mode
|
||||
if (creator.fieldMode && creator.fieldMode == 1) {
|
||||
var fields = {
|
||||
lastName: creator.lastName,
|
||||
fieldMode: 1
|
||||
};
|
||||
}
|
||||
// Two-field mode
|
||||
else {
|
||||
var fields = {
|
||||
firstName: creator.firstName,
|
||||
lastName: creator.lastName
|
||||
};
|
||||
}
|
||||
|
||||
var creator = null;
|
||||
var creatorDataID = Zotero.Creators.getDataID(fields);
|
||||
if(creatorDataID) {
|
||||
var linkedCreators = Zotero.Creators.getCreatorsWithData(creatorDataID, this._libraryID);
|
||||
if (linkedCreators) {
|
||||
// TODO: support identical creators via popup? ugh...
|
||||
var creatorID = linkedCreators[0];
|
||||
creator = Zotero.Creators.get(creatorID);
|
||||
}
|
||||
}
|
||||
if(!creator) {
|
||||
creator = new Zotero.Creator;
|
||||
creator.libraryID = this._libraryID;
|
||||
creator.setFields(fields);
|
||||
var creatorID = creator.save();
|
||||
}
|
||||
|
||||
newItem.setCreator(i, creator, creatorTypeID);
|
||||
}
|
||||
},
|
||||
|
||||
"_saveNotes":function(item, parentID) {
|
||||
for each(var note in item.notes) {
|
||||
var myNote = new Zotero.Item('note');
|
||||
myNote.libraryID = this._libraryID;
|
||||
myNote.setNote(typeof note == "object" ? note.note : note);
|
||||
if (myID) {
|
||||
myNote.setSource(myID);
|
||||
}
|
||||
var noteID = myNote.save();
|
||||
|
||||
if(typeof note == "object") {
|
||||
// handle see also
|
||||
myNote = Zotero.Items.get(noteID);
|
||||
this._saveTags(note, myNote);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"_saveTags":function(item, newItem) {
|
||||
// add to ID map
|
||||
if(item.itemID) {
|
||||
this._IDMap[item.itemID] = newItem.id;
|
||||
}
|
||||
|
||||
// add see alsos
|
||||
if(item.seeAlso) {
|
||||
for each(var seeAlso in item.seeAlso) {
|
||||
if(this._IDMap[seeAlso]) {
|
||||
newItem.addRelatedItem(this._IDMap[seeAlso]);
|
||||
}
|
||||
}
|
||||
newItem.save();
|
||||
}
|
||||
|
||||
// add tags
|
||||
if(item.tags) {
|
||||
var tagsToAdd = {};
|
||||
tagsToAdd[0] = []; // user tags
|
||||
tagsToAdd[1] = []; // automatic tags
|
||||
|
||||
for each(var tag in item.tags) {
|
||||
if(typeof(tag) == "string") {
|
||||
// accept strings in tag array as automatic tags, or, if
|
||||
// importing, as non-automatic tags
|
||||
if(this._forceTagType) {
|
||||
tagsToAdd[this._forceTagType].push(tag);
|
||||
} else {
|
||||
tagsToAdd[1].push(tag);
|
||||
}
|
||||
} else if(typeof(tag) == "object") {
|
||||
// also accept objects
|
||||
if(tag.tag) {
|
||||
if(this._forceTagType) {
|
||||
var tagType = this._forceTagType;
|
||||
} else if(tag.type) {
|
||||
var tagType = tag.type;
|
||||
} else {
|
||||
var tagType = 0;
|
||||
}
|
||||
|
||||
if(!tagsToAdd[tag.type]) {
|
||||
tagsToAdd[tag.type] = [];
|
||||
}
|
||||
tagsToAdd[tag.type].push(tag.tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var type in tagsToAdd) {
|
||||
if (tagsToAdd[type].length) {
|
||||
newItem.addTags(tagsToAdd[type], type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Translate.ItemGetter = function() {
|
||||
this._itemsLeft = null;
|
||||
this._collectionsLeft = null;
|
||||
this._exportFileDirectory = null;
|
||||
};
|
||||
|
||||
Zotero.Translate.ItemGetter.prototype = {
|
||||
"setItems":function(items) {
|
||||
this._itemsLeft = items;
|
||||
},
|
||||
|
||||
"setCollection":function(collection, getChildCollections) {
|
||||
// get items in this collection
|
||||
this._itemsLeft = collection.getChildItems();
|
||||
if(!this._itemsLeft) {
|
||||
this._itemsLeft = [];
|
||||
}
|
||||
|
||||
if(getChildCollections) {
|
||||
// get child collections
|
||||
this._collectionsLeft = Zotero.getCollections(collection.id, true);
|
||||
|
||||
if(this._collectionsLeft.length) {
|
||||
// only include parent collection if there are actually children
|
||||
this._collectionsLeft.unshift(getChildren);
|
||||
}
|
||||
|
||||
// get items in child collections
|
||||
for each(var collection in this._collectionsLeft) {
|
||||
var childItems = collection.getChildItems();
|
||||
if(childItems) {
|
||||
this._itemsLeft = this._itemsLeft.concat(childItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"setAll":function(getChildCollections) {
|
||||
this._itemsLeft = Zotero.Items.getAll(true);
|
||||
|
||||
if(getChildCollections) {
|
||||
this._collectionsLeft = Zotero.getCollections();
|
||||
}
|
||||
},
|
||||
|
||||
"exportFiles":function(dir) {
|
||||
// generate directory
|
||||
var directory = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
directory.initWithFile(this.location.parent);
|
||||
|
||||
// delete this file if it exists
|
||||
if(dir.exists()) {
|
||||
dir.remove(true);
|
||||
}
|
||||
|
||||
// get name
|
||||
var name = this.location.leafName;
|
||||
directory.append(name);
|
||||
|
||||
// create directory
|
||||
directory.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
|
||||
|
||||
// generate a new location for the exported file, with the appropriate
|
||||
// extension
|
||||
var location = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
location.initWithFile(directory);
|
||||
location.append(name+"."+this.translator[0].target);
|
||||
|
||||
// create files directory
|
||||
this._exportFileDirectory = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
this._exportFileDirectory.initWithFile(directory);
|
||||
this._exportFileDirectory.append("files");
|
||||
this._exportFileDirectory.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
|
||||
|
||||
return location;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts an attachment to array format and copies it to the export folder if desired
|
||||
*/
|
||||
"_attachmentToArray":function(attachment) {
|
||||
var attachmentArray = this._itemToArray(attachment);
|
||||
|
||||
var linkMode = attachment.getAttachmentLinkMode();
|
||||
|
||||
// get mime type
|
||||
attachmentArray.mimeType = attachmentArray.uniqueFields.mimeType = attachment.getAttachmentMIMEType();
|
||||
// get charset
|
||||
attachmentArray.charset = attachmentArray.uniqueFields.charset = attachment.getAttachmentCharset();
|
||||
|
||||
if(linkMode != Zotero.Attachments.LINK_MODE_LINKED_URL && this._exportFileDirectory) {
|
||||
// add path and filename if not an internet link
|
||||
var file = attachment.getFile();
|
||||
attachmentArray.path = "files/"+attachmentArray.itemID+"/"+file.leafName;
|
||||
|
||||
if(linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE) {
|
||||
// create a new directory
|
||||
var directory = Components.classes["@mozilla.org/file/local;1"].
|
||||
createInstance(Components.interfaces.nsILocalFile);
|
||||
directory.initWithFile(this._exportFileDirectory);
|
||||
directory.append(attachmentArray.itemID);
|
||||
// copy file
|
||||
try {
|
||||
directory.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700);
|
||||
file.copyTo(directory, attachmentArray.filename);
|
||||
} catch(e) {
|
||||
attachmentArray.path = undefined;
|
||||
}
|
||||
} else {
|
||||
// copy imported files from the Zotero directory
|
||||
var directory = file.parent;
|
||||
try {
|
||||
directory.copyTo(this._exportFileDirectory, attachmentArray.itemID);
|
||||
} catch(e) {
|
||||
attachmentArray.path = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attachmentArray.itemType = "attachment";
|
||||
|
||||
return attachmentArray;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts an item to array format
|
||||
*/
|
||||
"_itemToArray":function(returnItem) {
|
||||
const makeGetter = function(returnItemArray, fieldName) {
|
||||
return function() { return returnItemArray[fieldName] };
|
||||
}
|
||||
|
||||
// TODO use Zotero.Item#serialize()
|
||||
var returnItemArray = returnItem.toArray();
|
||||
|
||||
// Remove SQL date from multipart dates
|
||||
if (returnItemArray.date) {
|
||||
returnItemArray.date = Zotero.Date.multipartToStr(returnItemArray.date);
|
||||
}
|
||||
|
||||
returnItemArray.uniqueFields = {};
|
||||
|
||||
// get base fields, not just the type-specific ones
|
||||
var itemTypeID = returnItem.itemTypeID;
|
||||
var allFields = Zotero.ItemFields.getItemTypeFields(itemTypeID);
|
||||
for each(var field in allFields) {
|
||||
var fieldName = Zotero.ItemFields.getName(field);
|
||||
|
||||
if(returnItemArray[fieldName] !== undefined) {
|
||||
var baseField = Zotero.ItemFields.getBaseIDFromTypeAndField(itemTypeID, field);
|
||||
|
||||
var baseName = null;
|
||||
if(baseField && baseField != field) {
|
||||
baseName = Zotero.ItemFields.getName(baseField);
|
||||
}
|
||||
|
||||
if(baseName) {
|
||||
returnItemArray.__defineGetter__(baseName, makeGetter(returnItemArray, fieldName));
|
||||
returnItemArray.uniqueFields.__defineGetter__(baseName, makeGetter(returnItemArray, fieldName));
|
||||
} else {
|
||||
returnItemArray.uniqueFields.__defineGetter__(fieldName, makeGetter(returnItemArray, fieldName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// preserve notes
|
||||
if(returnItemArray.note) returnItemArray.uniqueFields.note = returnItemArray.note;
|
||||
|
||||
// TODO: Change tag.tag references in translators to tag.name
|
||||
// once translators are 1.5-only
|
||||
// TODO: Preserve tag type?
|
||||
if (returnItemArray.tags) {
|
||||
for (var i in returnItemArray.tags) {
|
||||
returnItemArray.tags[i].tag = returnItemArray.tags[i].fields.name;
|
||||
}
|
||||
}
|
||||
|
||||
return returnItemArray;
|
||||
},
|
||||
|
||||
"nextItem":function() {
|
||||
while(this._itemsLeft.length != 0) {
|
||||
var returnItem = this._itemsLeft.shift();
|
||||
// export file data for single files
|
||||
if(returnItem.isAttachment()) { // an independent attachment
|
||||
var returnItemArray = this._attachmentToArray(returnItem);
|
||||
if(returnItemArray) return returnItemArray;
|
||||
} else {
|
||||
returnItemArray = this._itemToArray(returnItem);
|
||||
|
||||
// get attachments, although only urls will be passed if exportFileData
|
||||
// is off
|
||||
returnItemArray.attachments = new Array();
|
||||
var attachments = returnItem.getAttachments();
|
||||
for each(var attachmentID in attachments) {
|
||||
var attachment = Zotero.Items.get(attachmentID);
|
||||
var attachmentInfo = this._attachmentToArray(attachment);
|
||||
|
||||
if(attachmentInfo) {
|
||||
returnItemArray.attachments.push(attachmentInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return returnItemArray;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
"nextCollection":function() {
|
||||
if(!this._collectionsLeft || !this._collectionsLeft.length == 0) return false;
|
||||
|
||||
var returnItem = this._collectionsLeft.shift();
|
||||
var obj = returnItem.serialize(true);
|
||||
obj.id = obj.primary.collectionID;
|
||||
obj.name = obj.fields.name;
|
||||
return obj;
|
||||
}
|
||||
}
|
1671
chrome/content/zotero/xpcom/translation/translate.js
Normal file
1671
chrome/content/zotero/xpcom/translation/translate.js
Normal file
File diff suppressed because it is too large
Load diff
405
chrome/content/zotero/xpcom/translation/translator.js
Normal file
405
chrome/content/zotero/xpcom/translation/translator.js
Normal file
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
***** 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 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
// Enumeration of types of translators
|
||||
const TRANSLATOR_TYPES = {"import":1, "export":2, "web":4, "search":8};
|
||||
|
||||
/**
|
||||
* Singleton to handle loading and caching of translators
|
||||
* @namespace
|
||||
*/
|
||||
Zotero.Translators = new function() {
|
||||
var _cache, _translators;
|
||||
var _initialized = false;
|
||||
|
||||
/**
|
||||
* Initializes translator cache, loading all relevant translators into memory
|
||||
*/
|
||||
this.init = function() {
|
||||
_initialized = true;
|
||||
|
||||
var start = (new Date()).getTime();
|
||||
var transactionStarted = false;
|
||||
|
||||
Zotero.UnresponsiveScriptIndicator.disable();
|
||||
|
||||
// Use try/finally so that we always reset the unresponsive script warning
|
||||
try {
|
||||
_cache = {"import":[], "export":[], "web":[], "search":[]};
|
||||
_translators = {};
|
||||
|
||||
var dbCacheResults = Zotero.DB.query("SELECT leafName, translatorJSON, "+
|
||||
"code, lastModifiedTime FROM translatorCache");
|
||||
var dbCache = {};
|
||||
for each(var cacheEntry in dbCacheResults) {
|
||||
dbCache[cacheEntry.leafName] = cacheEntry;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var filesInCache = {};
|
||||
var contents = Zotero.getTranslatorsDirectory().directoryEntries;
|
||||
while(contents.hasMoreElements()) {
|
||||
var file = contents.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
var leafName = file.leafName;
|
||||
if(!leafName || leafName[0] == ".") continue;
|
||||
var lastModifiedTime = file.lastModifiedTime;
|
||||
|
||||
var dbCacheEntry = false;
|
||||
if(dbCache[leafName]) {
|
||||
filesInCache[leafName] = true;
|
||||
if(dbCache[leafName].lastModifiedTime == lastModifiedTime) {
|
||||
dbCacheEntry = dbCache[file.leafName];
|
||||
}
|
||||
}
|
||||
|
||||
if(dbCacheEntry) {
|
||||
// get JSON from cache if possible
|
||||
var translator = new Zotero.Translator(file, dbCacheEntry.translatorJSON, dbCacheEntry.code);
|
||||
filesInCache[leafName] = true;
|
||||
} else {
|
||||
// otherwise, load from file
|
||||
var translator = new Zotero.Translator(file);
|
||||
}
|
||||
|
||||
if(translator.translatorID) {
|
||||
if(_translators[translator.translatorID]) {
|
||||
// same translator is already cached
|
||||
translator.logError('Translator with ID '+
|
||||
translator.translatorID+' already loaded from "'+
|
||||
_translators[translator.translatorID].file.leafName+'"');
|
||||
} else {
|
||||
// add to cache
|
||||
_translators[translator.translatorID] = translator;
|
||||
for(var type in TRANSLATOR_TYPES) {
|
||||
if(translator.translatorType & TRANSLATOR_TYPES[type]) {
|
||||
_cache[type].push(translator);
|
||||
}
|
||||
}
|
||||
|
||||
if(!dbCacheEntry) {
|
||||
// Add cache misses to DB
|
||||
if(!transactionStarted) {
|
||||
transactionStarted = true;
|
||||
Zotero.DB.beginTransaction();
|
||||
}
|
||||
Zotero.Translators.cacheInDB(leafName, translator.metadataString, translator.cacheCode ? translator.code : null, lastModifiedTime);
|
||||
delete translator.metadataString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// Remove translators from DB as necessary
|
||||
for(var leafName in dbCache) {
|
||||
if(!filesInCache[leafName]) {
|
||||
Zotero.DB.query("DELETE FROM translatorCache WHERE leafName = ?", [leafName]);
|
||||
}
|
||||
}
|
||||
|
||||
// Close transaction
|
||||
if(transactionStarted) {
|
||||
Zotero.DB.commitTransaction();
|
||||
}
|
||||
|
||||
// Sort by priority
|
||||
var collation = Zotero.getLocaleCollation();
|
||||
var cmp = function (a, b) {
|
||||
if (a.priority > b.priority) {
|
||||
return 1;
|
||||
}
|
||||
else if (a.priority < b.priority) {
|
||||
return -1;
|
||||
}
|
||||
return collation.compareString(1, a.label, b.label);
|
||||
}
|
||||
for(var type in _cache) {
|
||||
_cache[type].sort(cmp);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Zotero.UnresponsiveScriptIndicator.enable();
|
||||
}
|
||||
|
||||
Zotero.debug("Cached "+i+" translators in "+((new Date()).getTime() - start)+" ms");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translator that corresponds to a given ID
|
||||
*/
|
||||
this.get = function(id) {
|
||||
if(!_initialized) this.init();
|
||||
return _translators[id] ? _translators[id] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all translators for a specific type of translation
|
||||
*/
|
||||
this.getAllForType = function(type) {
|
||||
if(!_initialized) this.init();
|
||||
return _cache[type].slice(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} label
|
||||
* @return {String}
|
||||
*/
|
||||
this.getFileNameFromLabel = function(label) {
|
||||
return Zotero.File.getValidFileName(label) + ".js";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {String} metadata
|
||||
* @param {String} metadata.translatorID Translator GUID
|
||||
* @param {Integer} metadata.translatorType See TRANSLATOR_TYPES in translate.js
|
||||
* @param {String} metadata.label Translator title
|
||||
* @param {String} metadata.creator Translator author
|
||||
* @param {String|Null} metadata.target Target regexp
|
||||
* @param {String|Null} metadata.minVersion
|
||||
* @param {String} metadata.maxVersion
|
||||
* @param {Integer} metadata.priority
|
||||
* @param {Boolean} metadata.inRepository
|
||||
* @param {String} metadata.lastUpdated SQL date
|
||||
* @param {String} code
|
||||
* @return {nsIFile}
|
||||
*/
|
||||
this.save = function(metadata, code) {
|
||||
if (!metadata.translatorID) {
|
||||
throw ("metadata.translatorID not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.translatorType) {
|
||||
var found = false;
|
||||
for each(var type in TRANSLATOR_TYPES) {
|
||||
if (metadata.translatorType & type) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw ("Invalid translatorType '" + metadata.translatorType + "' in Zotero.Translators.save()");
|
||||
}
|
||||
}
|
||||
|
||||
if (!metadata.label) {
|
||||
throw ("metadata.label not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.priority) {
|
||||
throw ("metadata.priority not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!metadata.lastUpdated) {
|
||||
throw ("metadata.lastUpdated not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
throw ("code not provided in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
var fileName = Zotero.Translators.getFileNameFromLabel(metadata.label);
|
||||
var destFile = Zotero.getTranslatorsDirectory();
|
||||
destFile.append(fileName);
|
||||
|
||||
var metadataJSON;
|
||||
|
||||
// JSON.stringify (FF 3.5.4 and up) has the benefit of indenting JSON
|
||||
if (typeof JSON != "undefined" && 'function' == typeof JSON.stringify) {
|
||||
metadataJSON = JSON.stringify(metadata,null,8);
|
||||
} else {
|
||||
var nsIJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
|
||||
metadataJSON = nsIJSON.encode(metadata);
|
||||
}
|
||||
|
||||
var str = metadataJSON + "\n\n" + code;
|
||||
|
||||
var translator = Zotero.Translators.get(metadata.translatorID);
|
||||
if (translator && destFile.equals(translator.file)) {
|
||||
var sameFile = true;
|
||||
}
|
||||
|
||||
if (!sameFile && destFile.exists()) {
|
||||
var msg = "Overwriting translator with same filename '"
|
||||
+ fileName + "'";
|
||||
Zotero.debug(msg, 1);
|
||||
Zotero.debug(metadata, 1);
|
||||
Components.utils.reportError(msg + " in Zotero.Translators.save()");
|
||||
}
|
||||
|
||||
if (translator && translator.file.exists()) {
|
||||
translator.file.remove(false);
|
||||
}
|
||||
|
||||
Zotero.debug("Saving translator '" + metadata.label + "'");
|
||||
Zotero.debug(str);
|
||||
Zotero.File.putContents(destFile, str);
|
||||
|
||||
return destFile;
|
||||
}
|
||||
|
||||
this.cacheInDB = function(fileName, metadataJSON, code, lastModifiedTime) {
|
||||
Zotero.DB.query("REPLACE INTO translatorCache VALUES (?, ?, ?, ?)",
|
||||
[fileName, metadataJSON, code, lastModifiedTime]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Represents an individual translator
|
||||
* @constructor
|
||||
* @param {nsIFile} file File from which to generate a translator object
|
||||
* @property {String} translatorID Unique GUID of the translator
|
||||
* @property {Integer} translatorType Type of the translator (use bitwise & with TRANSLATOR_TYPES to read)
|
||||
* @property {String} label Human-readable name of the translator
|
||||
* @property {String} creator Author(s) of the translator
|
||||
* @property {String} target Location that the translator processes
|
||||
* @property {String} minVersion Minimum Zotero version
|
||||
* @property {String} maxVersion Minimum Zotero version
|
||||
* @property {Integer} priority Lower-priority translators will be selected first
|
||||
* @property {String} browserSupport String indicating browser supported by the translator
|
||||
* g = Gecko (Firefox)
|
||||
* c = Google Chrome (WebKit & V8)
|
||||
* s = Safari (WebKit & Nitro/Squirrelfish Extreme)
|
||||
* i = Internet Explorer
|
||||
* @property {Object} configOptions Configuration options for import/export
|
||||
* @property {Object} displayOptions Display options for export
|
||||
* @property {Boolean} inRepository Whether the translator may be found in the repository
|
||||
* @property {String} lastUpdated SQL-style date and time of translator's last update
|
||||
* @property {String} code The executable JavaScript for the translator
|
||||
*/
|
||||
Zotero.Translator = function(file, json, code) {
|
||||
const codeGetterFunction = function() { return Zotero.File.getContents(this.file); }
|
||||
// Maximum length for the info JSON in a translator
|
||||
const MAX_INFO_LENGTH = 4096;
|
||||
const infoRe = /^\s*{[\S\s]*?}\s*?[\r\n]/;
|
||||
|
||||
this.file = file;
|
||||
|
||||
if(json) {
|
||||
var info = Zotero.JSON.unserialize(json);
|
||||
} else {
|
||||
var fStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var cStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
fStream.init(file, -1, -1, 0);
|
||||
cStream.init(fStream, "UTF-8", 8192,
|
||||
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
|
||||
var str = {};
|
||||
cStream.readString(MAX_INFO_LENGTH, str);
|
||||
|
||||
// We assume lastUpdated is at the end to avoid running the regexp on more than necessary
|
||||
var lastUpdatedIndex = str.value.indexOf('"lastUpdated"');
|
||||
if (lastUpdatedIndex == -1) {
|
||||
this.logError("Invalid or missing translator metadata JSON object in " + file.leafName);
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add 50 characters to clear lastUpdated timestamp and final "}"
|
||||
var header = str.value.substr(0, lastUpdatedIndex + 50);
|
||||
var m = infoRe.exec(header);
|
||||
if (!m) {
|
||||
this.logError("Invalid or missing translator metadata JSON object in " + file.leafName);
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.metadataString = m[0];
|
||||
|
||||
try {
|
||||
var info = Zotero.JSON.unserialize(this.metadataString);
|
||||
} catch(e) {
|
||||
this.logError("Invalid or missing translator metadata JSON object in " + file.leafName);
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var haveMetadata = true;
|
||||
// make sure we have all the properties
|
||||
for each(var property in ["translatorID", "translatorType", "label", "creator", "target", "minVersion", "maxVersion", "priority", "lastUpdated", "inRepository"]) {
|
||||
if(info[property] === undefined) {
|
||||
this.logError('Missing property "'+property+'" in translator metadata JSON object in ' + file.leafName);
|
||||
haveMetadata = false;
|
||||
break;
|
||||
} else {
|
||||
this[property] = info[property];
|
||||
}
|
||||
}
|
||||
if(!haveMetadata) {
|
||||
fStream.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.configOptions = info["configOptions"] ? info["configOptions"] : {};
|
||||
this.displayOptions = info["displayOptions"] ? info["displayOptions"] : {};
|
||||
this.browserSupport = info["browserSupport"] ? info["browserSupport"] : "g";
|
||||
|
||||
if(this.translatorType & TRANSLATOR_TYPES["import"]) {
|
||||
// compile import regexp to match only file extension
|
||||
this.importRegexp = this.target ? new RegExp("\\."+this.target+"$", "i") : null;
|
||||
}
|
||||
|
||||
this.cacheCode = false;
|
||||
if(this.translatorType & TRANSLATOR_TYPES["web"]) {
|
||||
// compile web regexp
|
||||
this.webRegexp = this.target ? new RegExp(this.target, "i") : null;
|
||||
|
||||
if(!this.target) {
|
||||
this.cacheCode = true;
|
||||
|
||||
if(json) {
|
||||
// if have JSON, also have code
|
||||
this.code = code;
|
||||
} else {
|
||||
// for translators used on every page, cache code in memory
|
||||
var strs = [str.value];
|
||||
var amountRead;
|
||||
while(amountRead = cStream.readString(8192, str)) strs.push(str.value);
|
||||
this.code = strs.join("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!this.cacheCode) this.__defineGetter__("code", codeGetterFunction);
|
||||
if(!json) cStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a translator-related error
|
||||
* @param {String} message The error message
|
||||
* @param {String} [type] The error type ("error", "warning", "exception", or "strict")
|
||||
* @param {String} [line] The text of the line on which the error occurred
|
||||
* @param {Integer} lineNumber
|
||||
* @param {Integer} colNumber
|
||||
*/
|
||||
Zotero.Translator.prototype.logError = function(message, type, line, lineNumber, colNumber) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
Zotero.log(message, type ? type : "error", ios.newFileURI(this.file).spec);
|
||||
}
|
|
@ -85,6 +85,7 @@ Zotero.Utilities = {
|
|||
*/
|
||||
"trim":function(/**String*/ s) {
|
||||
if (typeof(s) != "string") {
|
||||
a()
|
||||
throw "trim: argument must be a string";
|
||||
}
|
||||
|
||||
|
@ -271,7 +272,7 @@ Zotero.Utilities = {
|
|||
var pairs = matches[1].match(/([^ =]+)="([^"]+")/g);
|
||||
for(var j=0; j<pairs.length; j++) {
|
||||
var keyVal = pairs[j].split(/=/);
|
||||
attributes[keyVal[0]] = val.substr(1, keyVal[1].length - 2);
|
||||
attributes[keyVal[0]] = keyVal[1].substr(1, keyVal[1].length - 2);
|
||||
}
|
||||
|
||||
parts.push({
|
||||
|
@ -285,7 +286,7 @@ Zotero.Utilities = {
|
|||
|
||||
parts.push({
|
||||
type: 'text',
|
||||
text: split
|
||||
text: splits[i]
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -512,10 +513,14 @@ Zotero.Utilities = {
|
|||
* @type Boolean
|
||||
*/
|
||||
"itemTypeExists":function(type) {
|
||||
if(Zotero.ItemTypes.getID(type)) {
|
||||
return true;
|
||||
if(Zotero.isConnector) {
|
||||
return !!Zotero.Connector.Data.itemTypes[type];
|
||||
} else {
|
||||
return false;
|
||||
if(Zotero.ItemTypes.getID(type)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -526,12 +531,30 @@ Zotero.Utilities = {
|
|||
* @return {String[]} Creator types
|
||||
*/
|
||||
"getCreatorsForType":function(type) {
|
||||
var types = Zotero.CreatorTypes.getTypesForItemType(Zotero.ItemTypes.getID(type));
|
||||
var cleanTypes = new Array();
|
||||
for(var i=0; i<types.length; i++) {
|
||||
cleanTypes.push(types[i].name);
|
||||
if(Zotero.isConnector) {
|
||||
return Zotero.Connector.Data.itemTypes[type].creatorTypes.slice(0);
|
||||
} else {
|
||||
var types = Zotero.CreatorTypes.getTypesForItemType(Zotero.ItemTypes.getID(type));
|
||||
var cleanTypes = new Array();
|
||||
for(var i=0; i<types.length; i++) {
|
||||
cleanTypes.push(types[i].name);
|
||||
}
|
||||
return cleanTypes;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find valid creator types for a given item type
|
||||
*
|
||||
* @param {String} type Item type
|
||||
* @return {String[]} Creator types
|
||||
*/
|
||||
"fieldIsValidForType":function(field, type) {
|
||||
if(Zotero.isConnector) {
|
||||
return Zotero.Connector.Data.itemTypes[type].fields.slice(0);
|
||||
} else {
|
||||
return Zotero.ItemFields.isValidForType(field, Zotero.ItemTypes.getID(type));
|
||||
}
|
||||
return cleanTypes;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -542,10 +565,14 @@ Zotero.Utilities = {
|
|||
* @type Boolean
|
||||
*/
|
||||
"getLocalizedCreatorType":function(type) {
|
||||
try {
|
||||
return Zotero.getString("creatorTypes."+type);
|
||||
} catch(e) {
|
||||
return false;
|
||||
if(Zotero.isConnector) {
|
||||
return Zotero.Connector.Data.creatorTypes[type].localizedString;
|
||||
} else {
|
||||
try {
|
||||
return Zotero.getString("creatorTypes."+type);
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +583,6 @@ Zotero.Utilities = {
|
|||
*
|
||||
* @constructor
|
||||
* @augments Zotero.Utilities
|
||||
* @borrows Zotero.inArray as this.inArray
|
||||
* @borrows Zotero.Date.formatDate as this.formatDate
|
||||
* @borrows Zotero.Date.strToDate as this.strToDate
|
||||
* @borrows Zotero.Date.strToISO as this.strToISO
|
||||
|
@ -567,7 +593,7 @@ Zotero.Utilities = {
|
|||
* @param {Zotero.Translate} translate
|
||||
*/
|
||||
Zotero.Utilities.Translate = function(translate) {
|
||||
this.translate = translate;
|
||||
this._translate = translate;
|
||||
}
|
||||
|
||||
var tmp = function() {};
|
||||
|
@ -699,7 +725,7 @@ Zotero.Utilities.Translate.prototype.loadDocument = function(url, succeeded, fai
|
|||
* @ignore
|
||||
*/
|
||||
Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor, done, exception) {
|
||||
if(this.translate.locationIsProxied) {
|
||||
if(this._translate.locationIsProxied) {
|
||||
if(typeof(urls) == "string") {
|
||||
urls = [this._convertURL(urls)];
|
||||
} else {
|
||||
|
@ -712,9 +738,9 @@ 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 translate = this.translate;
|
||||
var translate = this._translate;
|
||||
var exception = function(e) {
|
||||
translate.error(false, e);
|
||||
translate.complete(false, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -729,7 +755,7 @@ Zotero.Utilities.Translate.prototype.processDocuments = function(urls, processor
|
|||
* @return {Document} DOM document object
|
||||
*/
|
||||
Zotero.Utilities.Translate.prototype.retrieveDocument = function(url) {
|
||||
if(this.translate.locationIsProxied) url = this._convertURL(url);
|
||||
if(this._translate.locationIsProxied) url = this._convertURL(url);
|
||||
|
||||
var mainThread = Zotero.mainThread;
|
||||
var loaded = false;
|
||||
|
@ -775,7 +801,7 @@ Zotero.Utilities.Translate.prototype.retrieveSource = function(url, body, header
|
|||
/* 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/. */
|
||||
if(this.translate.locationIsProxied) url = this._convertURL(url);
|
||||
if(this._translate.locationIsProxied) url = this._convertURL(url);
|
||||
if(!headers) headers = null;
|
||||
if(!responseCharset) responseCharset = null;
|
||||
|
||||
|
@ -832,7 +858,7 @@ Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, res
|
|||
}
|
||||
}
|
||||
} catch(e) {
|
||||
me.translate.error(false, e);
|
||||
me._translate.complete(false, e);
|
||||
}
|
||||
}, responseCharset);
|
||||
}
|
||||
|
@ -844,12 +870,12 @@ Zotero.Utilities.Translate.prototype.doGet = function(urls, processor, done, res
|
|||
Zotero.Utilities.Translate.prototype.doPost = function(url, body, onDone, headers, responseCharset) {
|
||||
url = this._convertURL(url);
|
||||
|
||||
var translate = this.translate;
|
||||
var translate = this._translate;
|
||||
Zotero.HTTP.doPost(url, body, function(xmlhttp) {
|
||||
try {
|
||||
onDone(xmlhttp.responseText, xmlhttp);
|
||||
} catch(e) {
|
||||
translate.error(false, e);
|
||||
translate.complete(false, e);
|
||||
}
|
||||
}, headers, responseCharset);
|
||||
}
|
||||
|
@ -866,7 +892,7 @@ Zotero.Utilities.Translate.prototype._convertURL = function(url) {
|
|||
const protocolRe = /^(?:(?:http|https|ftp):)/i;
|
||||
const fileRe = /^[^:]*/;
|
||||
|
||||
if(this.translate.locationIsProxied) {
|
||||
if(this._translate.locationIsProxied) {
|
||||
url = Zotero.Proxies.properToProxy(url);
|
||||
}
|
||||
if(protocolRe.test(url)) return url;
|
||||
|
@ -875,7 +901,14 @@ Zotero.Utilities.Translate.prototype._convertURL = function(url) {
|
|||
} else {
|
||||
return Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService).
|
||||
newURI(this.translate.location, "", null).resolve(url);
|
||||
newURI(this._translate.location, "", null).resolve(url);
|
||||
}
|
||||
}
|
||||
|
||||
Zotero.Utilities.Translate.prototype.__exposedProps__ = [];
|
||||
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__.push(j);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ var Zotero = new function(){
|
|||
this.chooseZoteroDirectory = chooseZoteroDirectory;
|
||||
this.debug = debug;
|
||||
this.log = log;
|
||||
this.logError = logError;
|
||||
this.getErrors = getErrors;
|
||||
this.getSystemInfo = getSystemInfo;
|
||||
this.varDump = varDump;
|
||||
|
@ -196,6 +197,7 @@ var Zotero = new function(){
|
|||
Components.classes["@mozilla.org/xre/app-info;1"].
|
||||
getService(Components.interfaces.nsIXULAppInfo);
|
||||
this.appName = appInfo.name;
|
||||
this.isFx = true;
|
||||
this.isFx3 = appInfo.platformVersion.indexOf('1.9') === 0;
|
||||
this.isFx35 = appInfo.platformVersion.indexOf('1.9.1') === 0;
|
||||
this.isFx31 = this.isFx35;
|
||||
|
@ -874,6 +876,15 @@ var Zotero = new function(){
|
|||
consoleService.logMessage(scriptError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a JS error to the Mozilla JS error console.
|
||||
* @param {Exception} err
|
||||
*/
|
||||
function logError(err) {
|
||||
log(err.message ? err.message : err.toString, "error",
|
||||
err.fileName ? err.fileName : null, null,
|
||||
err.lineNumber ? err.lineNumber : null, null);
|
||||
}
|
||||
|
||||
function getErrors(asStrings) {
|
||||
var errors = [];
|
||||
|
|
|
@ -107,7 +107,10 @@ var xpcomFiles = [
|
|||
'storage/zfs',
|
||||
'storage/webdav',
|
||||
'timeline',
|
||||
'translate',
|
||||
'translation/translator',
|
||||
'translation/translate',
|
||||
'translation/browser_firefox',
|
||||
'translation/item_local',
|
||||
'uri',
|
||||
'utilities',
|
||||
'zeroconf'
|
||||
|
|
|
@ -7,14 +7,12 @@
|
|||
"minVersion":"1.0.0b4.r1",
|
||||
"maxVersion":"",
|
||||
"priority":200,
|
||||
"configOptions":{"dataMode":"block"},
|
||||
"displayOptions":{"exportCharset":"UTF-8", "exportFileData":false},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2010-06-18 08:32:05"
|
||||
}
|
||||
|
||||
Zotero.configure("dataMode", "block");
|
||||
Zotero.addOption("exportCharset", "UTF-8");
|
||||
Zotero.addOption("exportFileData", false);
|
||||
|
||||
function detectImport() {
|
||||
var maxChars = 1048576; // 1MB
|
||||
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
"minVersion":"2.0",
|
||||
"maxVersion":"",
|
||||
"priority":50,
|
||||
"configOptions":{"getCollections":"true", "dataMode":"rdf/xml"},
|
||||
"displayOptions":{"exportNotes":true, "exportFileData":false},
|
||||
"inRepository":false,
|
||||
"lastUpdated":"2010-04-20 23:02:43"
|
||||
}
|
||||
|
||||
Zotero.configure("getCollections", true);
|
||||
Zotero.configure("dataMode", "rdf");
|
||||
Zotero.addOption("exportNotes", true);
|
||||
Zotero.addOption("exportFileData", false);
|
||||
|
||||
var n = {
|
||||
address:"http://schemas.talis.com/2005/address/schema#", // could also use vcard?
|
||||
bibo:"http://purl.org/ontology/bibo/",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"minVersion":"2.0",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"configOptions":{"getCollections":"true", "dataMode":"line"},
|
||||
"inRepository":false,
|
||||
"lastUpdated":"2010-10-09 07:21:37"
|
||||
}
|
||||
|
@ -70,8 +71,6 @@
|
|||
* piggy-back off of the perhaps more robust support in the core Zotero code.
|
||||
*/
|
||||
|
||||
Zotero.configure("dataMode", "line");
|
||||
|
||||
function detectWeb(doc, url) {
|
||||
var texts = [], text = "";
|
||||
var codes = doc.getElementsByTagName("code");
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
"minVersion":"2.0b6.3",
|
||||
"maxVersion":"",
|
||||
"priority":50,
|
||||
"configOptions":{"dataMode":"dom/xml"},
|
||||
"displayOptions":{"exportNotes":true},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2010-09-10 01:22:13"
|
||||
}
|
||||
|
||||
Zotero.addOption("exportNotes", true);
|
||||
Zotero.configure("dataMode", "xml/e4x");
|
||||
|
||||
function detectImport() {
|
||||
var name = Zotero.getXML().name();
|
||||
if (!name) {
|
||||
|
@ -30,7 +29,7 @@ function doExport() {
|
|||
|
||||
var item;
|
||||
while(item = Zotero.nextItem()) {
|
||||
var isPartialItem = Zotero.Utilities.inArray(item.itemType, partialItemTypes);
|
||||
var isPartialItem = partialItemTypes.indexOf(item.itemType) !== -1;
|
||||
|
||||
var mods = <mods />;
|
||||
|
||||
|
@ -197,10 +196,10 @@ function doExport() {
|
|||
originInfo += <publisher>{item.distributor}</publisher>;
|
||||
}
|
||||
if(item.date) {
|
||||
if(Zotero.Utilities.inArray(item.itemType, ["book", "bookSection"])) {
|
||||
if(["book", "bookSection"].indexOf(item.itemType) !== -1) {
|
||||
// Assume year is copyright date
|
||||
var dateType = "copyrightDate";
|
||||
} else if(Zotero.Utilities.inArray(item.itemType, ["journalArticle", "magazineArticle", "newspaperArticle"])) {
|
||||
} else if(["journalArticle", "magazineArticle", "newspaperArticle"].indexOf(item.itemType) !== -1) {
|
||||
// Assume date is date issued
|
||||
var dateType = "dateIssued";
|
||||
} else {
|
||||
|
@ -542,7 +541,7 @@ function doImport() {
|
|||
if(!newItem.itemType) newItem.itemType = "document";
|
||||
}
|
||||
|
||||
var isPartialItem = Zotero.Utilities.inArray(newItem.itemType, partialItemTypes);
|
||||
var isPartialItem = partialItemTypes.indexOf(newItem.itemType) !== -1;
|
||||
|
||||
// TODO: thesisType, type
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
"minVersion":"1.0.0b4.r1",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"configOptions":{"dataMode":"rdf/xml"},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2009-11-12 07:20:00"
|
||||
}
|
||||
|
||||
Zotero.configure("dataMode", "rdf");
|
||||
|
||||
function detectImport() {
|
||||
// unfortunately, Mozilla will let you create a data source from any type
|
||||
// of XML, so we need to make sure there are actually nodes
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"inRepository":true,
|
||||
"configOptions":{"dataMode":"block"},
|
||||
"displayOptions":{"exportCharset":"UTF-8", "exportNotes":true},
|
||||
"lastUpdated":"2010-09-28 21:40:00"
|
||||
}
|
||||
|
||||
Zotero.configure("dataMode", "line");
|
||||
Zotero.addOption("exportNotes", true);
|
||||
Zotero.addOption("exportCharset", "UTF-8");
|
||||
|
||||
function detectImport() {
|
||||
var line;
|
||||
var i = 0;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
"minVersion":"1.0.0b4.r5",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"configOptions":{"dataMode":"line"},
|
||||
"displayOptions":{"exportCharset":"UTF-8"},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2009-07-17 20:20:00"
|
||||
}
|
||||
|
||||
Zotero.configure("dataMode", "line");
|
||||
Zotero.addOption("exportCharset", "UTF-8");
|
||||
|
||||
function detectImport() {
|
||||
var lineRe = /%[A-Z0-9\*\$] .+/;
|
||||
var line;
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
"minVersion":"1.0.0b3.r1",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"configOptions":{"dataMode":"rdf/xml"},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2006-10-02 17:00:00"
|
||||
}
|
||||
|
||||
Zotero.configure("dataMode", "rdf");
|
||||
|
||||
function doExport() {
|
||||
var dc = "http://purl.org/dc/elements/1.1/";
|
||||
Zotero.RDF.addNamespace("dc", dc);
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
"minVersion":"1.0.0b4.r1",
|
||||
"maxVersion":"",
|
||||
"priority":100,
|
||||
"displayOptions":{"exportCharset":"UTF-8"},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2008-07-17 22:05:00"
|
||||
}
|
||||
|
||||
Zotero.addOption("exportCharset", "UTF-8");
|
||||
|
||||
var fieldMap = {
|
||||
edition:"edition",
|
||||
publisher:"publisher",
|
||||
|
|
|
@ -7,15 +7,12 @@
|
|||
"minVersion":"1.0.0b4.r1",
|
||||
"maxVersion":"",
|
||||
"priority":25,
|
||||
"configOptions":{"getCollections":"true", "dataMode":"rdf/xml"},
|
||||
"displayOptions":{"exportNotes":true, "exportFileData":false},
|
||||
"inRepository":true,
|
||||
"lastUpdated":"2010-10-10 02:07:05"
|
||||
}
|
||||
|
||||
Zotero.configure("getCollections", true);
|
||||
Zotero.configure("dataMode", "rdf");
|
||||
Zotero.addOption("exportNotes", true);
|
||||
Zotero.addOption("exportFileData", false);
|
||||
|
||||
var rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
|
||||
|
||||
var n = {
|
||||
|
|
Loading…
Add table
Reference in a new issue