Permalink
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
translators/BibLaTeX.js
Find file
Copy path
Fetching contributors…
Cannot retrieve contributors at this time
{ | |
"translatorID": "b6e39b57-8942-4d11-8259-342c46ce395f", | |
"translatorType": 2, | |
"label": "BibLaTeX", | |
"creator": "Simon Kornblith, Richard Karnesky and Anders Johansson", | |
"target": "bib", | |
"minVersion": "2.1.9", | |
"maxVersion": "null", | |
"priority": 100, | |
"inRepository": true, | |
"configOptions":{"getCollections": true}, | |
"displayOptions": { | |
"exportCharset": "UTF-8", | |
"exportNotes": false, | |
"exportFileData": false, | |
"useJournalAbbreviation": false | |
}, | |
"lastUpdated": "2019-01-31 13:16:00" | |
} | |
/* | |
***** BEGIN LICENSE BLOCK ***** | |
Copyright © 2019 Simon Kornblith, Richard Karnesky and Anders Johansson | |
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/>. | |
***** END LICENSE BLOCK ***** | |
*/ | |
//%a = first listed creator surname | |
//%y = year | |
//%t = first word of title | |
var citeKeyFormat = "%a_%t_%y"; | |
var fieldMap = { | |
location: "place", | |
chapter: "chapter", | |
edition: "edition", | |
title: "title", | |
volume: "volume", | |
rights: "rights", //it's rights in zotero nowadays | |
isbn: "ISBN", | |
issn: "ISSN", | |
url: "url", | |
doi: "DOI", | |
series: "series", | |
shorttitle: "shortTitle", | |
holder: "assignee", | |
abstract: "abstractNote", | |
volumes: "numberOfVolumes", | |
version: "version", | |
eventtitle: "conferenceName", | |
pages: "pages", | |
pagetotal: "numPages" | |
}; | |
//more conversions done below with special rules | |
/** | |
* Identifiers from item.extra | |
* Copied from BibTeX | |
*/ | |
// Exported in BibTeX and BibLaTeX | |
var revExtraIds = { | |
LCCN: 'lccn', | |
MR: 'mrnumber', | |
Zbl: 'zmnumber', | |
PMCID: 'pmcid', | |
PMID: 'pmid', | |
DOI: 'doi' | |
}; | |
// Imported by BibTeX. Exported by BibLaTeX only | |
var revEprintIds = { | |
// eprinttype: Zotero label | |
// From BibLaTeX manual | |
arXiv: 'arxiv', // Sorry, but no support for eprintclass yet | |
JSTOR: 'jstor', | |
//PMID: 'pubmed', // Not sure if we should do this instead | |
HDL: 'hdl', | |
GoogleBooksID: 'googlebooks' | |
}; | |
function parseExtraFields(extra) { | |
var lines = extra.split(/[\r\n]+/); | |
var fields = []; | |
for (var i=0; i<lines.length; i++) { | |
var rec = { raw: lines[i] }; | |
var line = lines[i].trim(); | |
var splitAt = line.indexOf(':'); | |
if (splitAt > 1) { | |
rec.field = line.substr(0,splitAt).trim(); | |
rec.value = line.substr(splitAt + 1).trim(); | |
} | |
fields.push(rec); | |
} | |
return fields; | |
} | |
function extraFieldsToString(extra) { | |
var str = ''; | |
for (var i=0; i<extra.length; i++) { | |
if (!extra[i].raw) { | |
str += '\n' + extra[i].field + ': ' + extra[i].value; | |
} else { | |
str += '\n' + extra[i].raw; | |
} | |
} | |
return str.substr(1); | |
} | |
//POTENTIAL ISSUES | |
//accessDate:"accessDate", //only written on attached webpage snapshots by zotero | |
var zotero2biblatexTypeMap = { | |
"book": "book", | |
"bookSection": "incollection", | |
"journalArticle": "article", | |
"magazineArticle": "article", | |
"newspaperArticle": "article", | |
"thesis": "thesis", | |
"letter": "letter", | |
"manuscript": "unpublished", | |
"interview": "misc", | |
"film": "movie", | |
"artwork": "artwork", | |
"webpage": "online", | |
"conferencePaper": "inproceedings", | |
"report": "report", | |
"bill": "legislation", | |
"case": "jurisdiction", | |
"hearing": "jurisdiction", | |
"patent": "patent", | |
"statute": "legislation", | |
"email": "letter", | |
"map": "misc", | |
"blogPost": "online", | |
"instantMessage": "misc", | |
"forumPost": "online", | |
"audioRecording": "audio", | |
"presentation": "unpublished", | |
"videoRecording": "video", | |
"tvBroadcast": "misc", | |
"radioBroadcast": "misc", | |
"podcast": "audio", | |
"computerProgram": "software", | |
"document": "misc", | |
"encyclopediaArticle": "inreference", | |
"dictionaryEntry": "inreference" | |
}; | |
var alwaysMap = { | |
"|": "{\\textbar}", | |
"<": "{\\textless}", | |
">": "{\\textgreater}", | |
"~": "{\\textasciitilde}", | |
"^": "{\\textasciicircum}", | |
"\\": "{\\textbackslash}", | |
"{": "\\{", | |
"}": "\\}" | |
}; | |
//to map ISO language codes (tries to follow IETF RFC5646) to babel | |
//language codes used in biblatex. Taken from Babel manual 3.9h. | |
var babelLanguageMap = { | |
"af": "afrikaans", | |
"ar": "arabic", | |
//bahasa (see malay and indonesian) | |
"eu": "basque", | |
"br": "breton", | |
"bg": "bulgarian", | |
"ca": "catalan", | |
"hr": "croatian", | |
"cz": "czech", | |
"da": "danish", | |
"nl": "dutch", | |
"en": { | |
"": "english", //same as american | |
"US": "american", | |
"GB": "british", | |
"CA": "canadian", | |
"AU": "australian", | |
"NZ": "newzealand" | |
}, | |
"eo": "esperanto", | |
"et": "estonian", | |
//ethiop (package for many languages) | |
"fa": "farsi", | |
"fi": "finnish", | |
"fr": { | |
"": "french", | |
"CA": "canadien" | |
//frenchle (a special package) | |
}, | |
"fur": "friulan", | |
"gl": "galician", | |
"de": { | |
"": "german", | |
"AT": "austrian", | |
"DE-1996": "ngerman", //these are valid IETF language codes | |
"AT-1996": "naustrian", | |
"1996": "ngerman" | |
}, | |
"el": { | |
"": "greek", | |
"polyton": "polutonikogreek" | |
}, | |
"he": "hebrew", | |
"hi": "hindi", | |
"is": "icelandic", | |
"id": "indonesian", //aliases: bahasai, indon | |
"ia": "interlingua", | |
"ga": "irish", | |
"it": "italian", | |
"ja": "japanese", | |
"la": "latin", | |
"lv": "latvian", | |
"lt": "lithuanian", | |
"dsb": "lowersorbian", | |
"hu": "magyar", | |
"zlm": "malay", //aliases: bahasam, melayu (currently, there's no | |
//real difference between bahasam and bahasai in babel) | |
"mn": "mongolian", | |
"se": "samin", | |
"nn": "nynorsk", //nynorsk | |
"nb": "norsk", //bokmål | |
"no": "norwegian", //"no" could be used, norwegian is an alias for "norsk" in babel | |
"zh": { | |
"": "pinyin", //only supported chinese in babel is the romanization pinyin? | |
"Latn": "pinyin" | |
}, | |
"pl": "polish", | |
"pt": { | |
"": "portuguese", | |
"PT": "portuguese", | |
"BR": "brazil" | |
}, | |
"ro": "romanian", | |
"rm": "romansh", | |
"ru": "russian", | |
"gd": "scottish", | |
"sr": { | |
"": "serbian", //latin script as default? | |
"Cyrl": "serbianc", | |
"Latn": "serbian", | |
}, | |
"sk": "slovak", | |
"sl": "slovene", | |
//spanglish (pseudo language) | |
"es": "spanish", | |
"sv": "swedish", | |
"th": "thaicjk", //thaicjk preferred? | |
"tr": "turkish", | |
"tk": "turkmen", | |
"uk": "ukrainian", | |
"hsb": "uppersorbian", | |
"vi": "vietnamese", | |
"cy": "welsh", | |
}; | |
// some fields are, in fact, macros. If that is the case then we should not put the | |
// data in the braces as it will cause the macros to not expand properly | |
function writeField(field, value, isMacro, noEscape) { | |
if (!value && typeof value != "number") return; | |
value = value + ""; // convert integers to strings | |
Zotero.write(",\n\t" + field + " = "); | |
if (!isMacro) Zotero.write("{"); | |
// url field is preserved, for use with \href and \url | |
// Other fields (DOI?) may need similar treatment | |
if (!noEscape && !isMacro && !(field == "url" || field == "doi" || field == "file" || field == "lccn")) { | |
//var titleCase = isTitleCase(value); //figure this out before escaping all the characters | |
// I hope these are all the escape characters! (except for < > which are handled later) | |
value = value.replace(/[|\~\^\\\{\}]/g, mapEscape).replace(/[\#\$\%\&\_]/g, "\\$&"); | |
//convert the HTML markup allowed in Zotero for rich text to TeX | |
value = mapHTMLmarkup(value); | |
//escape < > if mapHTMLmarkup did not convert some | |
value = value.replace(/[<>]/g, mapEscape); | |
// Case of words with uppercase characters in non-initial positions is preserved with braces. | |
// we're looking at all unicode letters | |
var protectCaps = new ZU.XRegExp("\\b\\p{Letter}+\\p{Uppercase_Letter}\\p{Letter}*", 'g'); | |
if (field != "pages") { | |
value = ZU.XRegExp.replace(value, protectCaps, "{$0}"); | |
} | |
// Page ranges should use double dash | |
if (field == "pages") { | |
value = value.replace(/[-\u2012-\u2015\u2053]+/g,"--"); | |
} | |
} | |
//we write utf8 | |
//convert the HTML markup allowed in Zotero for rich text to TeX; excluding doi/url/file shouldn't be necessary, but better to be safe; | |
if (!((field == "url") || (field == "doi") || (field == "file"))) value = mapHTMLmarkup(value); | |
Zotero.write(value); | |
if (!isMacro) Zotero.write("}"); | |
} | |
function mapHTMLmarkup(characters) { | |
//converts the HTML markup allowed in Zotero for rich text to TeX | |
//since < and > have already been escaped, we need this rather hideous code - I couldn't see a way around it though. | |
//italics and bold | |
characters = characters.replace(/\{\\textless\}i\{\\textgreater\}(((?!\{\\textless\}\/i{\\textgreater\}).)+)\{\\textless\}\/i{\\textgreater\}/, "\\textit{$1}").replace(/\{\\textless\}b\{\\textgreater\}(((?!\{\\textless\}\/b{\\textgreater\}).)+)\{\\textless\}\/b{\\textgreater\}/g, "\\textbf{$1}"); | |
//sub and superscript | |
characters = characters.replace(/\{\\textless\}sup\{\\textgreater\}(((?!\{\\textless\}\/sup\{\\textgreater\}).)+)\{\\textless\}\/sup{\\textgreater\}/g, "\$^{\\textrm{$1}}\$").replace(/\{\\textless\}sub\{\\textgreater\}(((?!\{\\textless\}\/sub\{\\textgreater\}).)+)\{\\textless\}\/sub\{\\textgreater\}/g, "\$_{\\textrm{$1}}\$"); | |
//two variants of small caps | |
characters = characters.replace(/\{\\textless\}span\sstyle=\"small\-caps\"\{\\textgreater\}(((?!\{\\textless\}\/span\{\\textgreater\}).)+)\{\\textless\}\/span{\\textgreater\}/g, "\\textsc{$1}").replace(/\{\\textless\}sc\{\\textgreater\}(((?!\{\\textless\}\/sc\{\\textgreater\}).)+)\{\\textless\}\/sc\{\\textgreater\}/g, "\\textsc{$1}"); | |
return characters; | |
} | |
function mapEscape(character) { | |
return alwaysMap[character]; | |
} | |
// a little substitution function for BibTeX keys, where we don't want LaTeX | |
// escaping, but we do want to preserve the base characters | |
function tidyAccents(s) { | |
var r = s.toLowerCase(); | |
// XXX Remove conditional when we drop Zotero 2.1.x support | |
// This is supported in Zotero 3.0 and higher | |
if (ZU.removeDiacritics !== undefined) | |
r = ZU.removeDiacritics(r, true); | |
else { | |
// We fall back on the replacement list we used previously | |
r = r.replace(new RegExp("[ä]", 'g'), "ae"); | |
r = r.replace(new RegExp("[ö]", 'g'), "oe"); | |
r = r.replace(new RegExp("[ü]", 'g'), "ue"); | |
r = r.replace(new RegExp("[àáâãå]", 'g'), "a"); | |
r = r.replace(new RegExp("æ", 'g'), "ae"); | |
r = r.replace(new RegExp("ç", 'g'), "c"); | |
r = r.replace(new RegExp("[èéêë]", 'g'), "e"); | |
r = r.replace(new RegExp("[ìíîï]", 'g'), "i"); | |
r = r.replace(new RegExp("ñ", 'g'), "n"); | |
r = r.replace(new RegExp("[òóôõ]", 'g'), "o"); | |
r = r.replace(new RegExp("œ", 'g'), "oe"); | |
r = r.replace(new RegExp("[ùúû]", 'g'), "u"); | |
r = r.replace(new RegExp("[ýÿ]", 'g'), "y"); | |
} | |
return r; | |
}; | |
var numberRe = /^[0-9]+/; | |
// Below is a list of words that should not appear as part of the citation key | |
// in includes the indefinite articles of English, German, French and Spanish, as well as a small set of English prepositions whose | |
// force is more grammatical than lexical, i.e. which are likely to strike many as 'insignificant'. | |
// The assumption is that most who want a title word in their key would prefer the first word of significance. | |
var citeKeyTitleBannedRe = /\b(a|an|the|some|from|on|in|to|of|do|with|der|die|das|ein|eine|einer|eines|einem|einen|un|une|la|le|l\'|el|las|los|al|uno|una|unos|unas|de|des|del|d\')(\s+|\b)|(<\/?(i|b|sup|sub|sc|span style=\"small-caps\"|span)>)/g; | |
var citeKeyConversionsRe = /%([a-zA-Z])/; | |
var citeKeyCleanRe = /[^a-z0-9\!\$\&\*\+\-\.\/\:\;\<\>\?\[\]\^\_\`\|]+/g; | |
var citeKeyConversions = { | |
"a": function (flags, item) { | |
if (item.creators && item.creators[0] && item.creators[0].lastName) { | |
return item.creators[0].lastName.toLowerCase().replace(/ /g, "_").replace(/,/g, ""); | |
} | |
return "noauthor"; | |
}, | |
"t": function (flags, item) { | |
if (item["title"]) { | |
return item["title"].toLowerCase().replace(citeKeyTitleBannedRe, "").split(/\s+/g)[0]; | |
} | |
return "notitle"; | |
}, | |
"y": function (flags, item) { | |
if (item.date) { | |
var date = Zotero.Utilities.strToDate(item.date); | |
if (date.year && numberRe.test(date.year)) { | |
return date.year; | |
} | |
} | |
return "nodate"; | |
} | |
}; | |
//checks whether an item contains any creator of type ctype | |
function creatorCheck(item, ctype) { | |
if (item.creators && item.creators.length) { | |
for (var i=0; i<item.creators.length; i++) { | |
if (item.creators[i].creatorType == ctype) { | |
return true; //found a ctype creator | |
} | |
} | |
} | |
//didn't find any ctype creator (or no creators at all) | |
return false; | |
} | |
function buildCiteKey (item, extraFields, citekeys) { | |
if (extraFields) { | |
const citationKey = extraFields.findIndex(field => field.field && field.value && field.field.toLowerCase() === 'citation key'); | |
if (citationKey >= 0) return extraFields.splice(citationKey, 1)[0].value; | |
} | |
if (item.citationKey) return item.citationKey; | |
var basekey = ""; | |
var counter = 0; | |
var citeKeyFormatRemaining = citeKeyFormat; | |
while (citeKeyConversionsRe.test(citeKeyFormatRemaining)) { | |
if (counter > 100) { | |
Zotero.debug("Pathological BibTeX format: " + citeKeyFormat); | |
break; | |
} | |
var m = citeKeyFormatRemaining.match(citeKeyConversionsRe); | |
if (m.index > 0) { | |
//add data before the conversion match to basekey | |
basekey = basekey + citeKeyFormatRemaining.substr(0, m.index); | |
} | |
var flags = ""; // for now | |
var f = citeKeyConversions[m[1]]; | |
if (typeof (f) == "function") { | |
var value = f(flags, item); | |
Zotero.debug("Got value " + value + " for %" + m[1]); | |
//add conversion to basekey | |
basekey = basekey + value; | |
} | |
citeKeyFormatRemaining = citeKeyFormatRemaining.substr(m.index + m.length); | |
counter++; | |
} | |
if (citeKeyFormatRemaining.length > 0) { | |
basekey = basekey + citeKeyFormatRemaining; | |
} | |
// for now, remove any characters not explicitly known to be allowed; | |
// we might want to allow UTF-8 citation keys in the future, depending | |
// on implementation support. | |
// | |
// no matter what, we want to make sure we exclude | |
// " # % ' ( ) , = { } ~ and backslash | |
// however, we want to keep the base characters | |
basekey = tidyAccents(basekey); | |
basekey = basekey.replace(citeKeyCleanRe, ""); | |
var citekey = basekey; | |
var i = 0; | |
while (citekeys[citekey]) { | |
i++; | |
citekey = basekey + "-" + i; | |
} | |
citekeys[citekey] = true; | |
return citekey; | |
} | |
var filePathSpecialChars = '\\\\:;{}$'; // $ for Mendeley | |
var encodeFilePathRE = new RegExp('[' + filePathSpecialChars + ']', 'g'); | |
function encodeFilePathComponent(value) { | |
if (!value) return ''; | |
return value.replace(encodeFilePathRE, "\\$&"); | |
} | |
function doExport() { | |
//Zotero.write("% biblatex export generated by Zotero "+Zotero.Utilities.getVersion()); | |
// to make sure the BOM gets ignored | |
Zotero.write("\n"); | |
var first = true; | |
var citekeys = new Object(); | |
var item; | |
while (item = Zotero.nextItem()) { | |
//don't export standalone notes and attachments | |
if (item.itemType == "note" || item.itemType == "attachment") continue; | |
var noteused = false; //a switch for keeping track whether the | |
//field "note" has been written to | |
// determine type | |
var type = zotero2biblatexTypeMap[item.itemType]; | |
if (typeof (type) == "function") { | |
type = type(item); | |
} | |
//inbook is reasonable at times, using a bookauthor should | |
//indicate this | |
if (item.itemType == "bookSection" && | |
creatorCheck(item, "bookAuthor")) type = "inbook"; | |
//a book without author but with editors is a collection | |
if (item.itemType == "book" && !creatorCheck(item,"author") && | |
creatorCheck(item, "editor")) type = "collection"; | |
//biblatex recommends us to use mvbook for multi-volume book | |
//i.e. a book with "# of vols" filled | |
if (type == "book" && item.numberOfVolumes) type = "mvbook"; | |
if (!type) type = "misc"; | |
var extraFields = item.extra ? parseExtraFields(item.extra) : null; | |
var citekey = buildCiteKey(item, extraFields, citekeys); | |
// write citation key (removed the comma) | |
Zotero.write((first ? "" : "\n\n") + "@" + type + "{" + citekey); | |
first = false; | |
for (var field in fieldMap) { | |
if (item[fieldMap[field]]) { | |
writeField(field, item[fieldMap[field]]); | |
} | |
} | |
// Fields needing special treatment and not easily translatable via fieldMap | |
//e.g. where fieldname translation is dependent upon type, or special transformations | |
//has to be made | |
//all kinds of numbers except patents, which need post-processing | |
if (item.reportNumber || item.seriesNumber || item.billNumber || item.episodeNumber || item.number && !item.patentNumber) { | |
writeField("number", item.reportNumber || item.seriesNumber || item.billNumber || item.episodeNumber || item.number); | |
} | |
//split numeric and nonnumeric issue specifications (for journals) into "number" and "issue" | |
if (item.issue) { //issue | |
var jnumber = parseInt(item.issue); | |
if (!isNaN(jnumber)) { | |
writeField("number", jnumber); | |
} else { | |
writeField("issue", item.issue); | |
} | |
} | |
//publicationTitles and special titles | |
if (item.publicationTitle) { | |
if (item.itemType == "bookSection" || item.itemType == "conferencePaper" || item.itemType == "dictionaryEntry" || item.itemType == "encyclopediaArticle") { | |
writeField("booktitle", item.publicationTitle); | |
} else if (item.itemType == "magazineArticle" || item.itemType == "newspaperArticle") { | |
writeField("journaltitle", item.publicationTitle); | |
} else if (item.itemType == "journalArticle") { | |
if (Zotero.getOption("useJournalAbbreviation") && item.journalAbbreviation) { | |
writeField("journaltitle", item.journalAbbreviation); | |
} else { | |
writeField("journaltitle", item.publicationTitle); | |
writeField("shortjournal", item.journalAbbreviation); | |
} | |
} | |
} | |
if (item.websiteTitle || item.forumTitle || item.blogTitle || item.programTitle) { | |
writeField("titleaddon", item.websiteTitle || item.forumTitle || item.blogTitle || item.programTitle); | |
} | |
//publishers | |
if (item.publisher) { | |
if (item.itemType == "thesis" || item.itemType == "report") { | |
writeField("institution", item.publisher); | |
} else { | |
writeField("publisher", item.publisher); | |
} | |
} | |
//things concerning "type" | |
if (item.itemType == "letter") { | |
if (item.letterType) { | |
writeField("type", item.letterType); | |
} else { | |
writeField("type", "Letter"); //this isn't optimal, perhaps later versions of biblatex will add some suitable localization key | |
} | |
} else if (item.itemType == "email") { | |
writeField("type", "E-mail"); | |
} else if (item.itemType == "thesis" && | |
(!item.thesisType || item.thesisType.search(/ph\.?d/i) != -1)) { | |
writeField("type", "phdthesis"); | |
} else if (item.manuscriptType || item.thesisType || item.websiteType || item.presentationType || item.reportType || item.mapType) { | |
writeField("type", item.manuscriptType || item.thesisType || item.websiteType || item.presentationType || item.reportType || item.mapType); | |
} else if (item.itemType == "patent") { | |
// see https://tex.stackexchange.com/questions/447383/biblatex-biber-patent-citation-support-based-on-zoterobbl-output/447508 | |
if (!item.patentNumber) { | |
writeField("type", "patent"); | |
} else if (item.patentNumber.startsWith("US")) { | |
writeField("type", "patentus"); | |
writeField("number", item.patentNumber.replace(/^US/, "")); | |
} else if (item.patentNumber.startsWith("EP")) { | |
writeField("type", "patenteu"); | |
writeField("number", item.patentNumber.replace(/^EP/, "")); | |
} else if (item.patentNumber.startsWith("GB")) { | |
writeField("type", "patentuk"); | |
writeField("number", item.patentNumber.replace(/^GB/, "")); | |
} else if (item.patentNumber.startsWith("DE")) { | |
writeField("type", "patentde"); | |
writeField("number", item.patentNumber.replace(/^DE/, "")); | |
} else if (item.patentNumber.startsWith("FR")) { | |
writeField("type", "patentfr"); | |
writeField("number", item.patentNumber.replace(/^FR/, "")); | |
} else { | |
writeField("type", "patent"); | |
writeField("number", item.patentNumber); | |
} | |
} | |
if (item.presentationType || item.manuscriptType) { | |
writeField("howpublished", item.presentationType || item.manuscriptType); | |
} | |
//case of specific eprint-archives in archive-fields | |
if (item.archive && item.archiveLocation) { | |
if (item.archive == "arXiv" || item.archive == "arxiv") { | |
writeField("eprinttype", "arxiv"); | |
writeField("eprint", item.archiveLocation); | |
if (item.callNumber) { //assume call number is used for arxiv class | |
writeField("eprintclass", item.callNumber); | |
} | |
} else if (item.archive = "JSTOR" || item.archive == "jstor") { | |
writeField("eprinttype", "jstor"); | |
writeField("eprint", item.archiveLocation); | |
} else if (item.archive = "PubMed" || item.archive == "pubmed") { | |
writeField("eprinttype", "pubmed"); | |
writeField("eprint", item.archiveLocation); | |
} else if (item.archive = "HDL" || item.archive == "hdl") { | |
writeField("eprinttype", "hdl"); | |
writeField("eprint", item.archiveLocation); | |
} else if (item.archive = "googlebooks" || item.archive == "Google Books") { | |
writeField("eprinttype", "googlebooks"); | |
writeField("eprint", item.archiveLocation); | |
} | |
} | |
//presentations have a meetingName field which we want to | |
//map to note | |
if (item.meetingName) { | |
writeField("note", item.meetingName); | |
noteused = true; | |
} | |
if (item.creators && item.creators.length) { | |
// split creators into subcategories | |
var author = ""; | |
var bookauthor = ""; | |
var commentator = ""; | |
var editor = ""; | |
var editora = ""; | |
var editorb = ""; | |
var holder = ""; | |
var translator = ""; | |
var noEscape = false; | |
for (var i=0; i<item.creators.length; i++) { | |
var creator = item.creators[i]; | |
var creatorString; | |
if (creator.firstName) { | |
var fname = creator.firstName.split(/\s*,!?\s*/); | |
fname.push(fname.shift()); // If we have a Jr. part(s), it should precede first name | |
creatorString = creator.lastName + ", " + fname.join(', '); | |
} else { | |
creatorString = creator.lastName; | |
} | |
creatorString = creatorString.replace(/[|\<\>\~\^\\\{\}]/g, mapEscape) | |
.replace(/([\#\$\%\&\_])/g, "\\$1"); | |
if (creator.fieldMode == true) { // fieldMode true, assume corporate author | |
creatorString = "{" + creatorString + "}"; | |
noEscape = true; | |
} else { | |
creatorString = creatorString.replace(/ (and) /gi, ' {$1} '); | |
} | |
if (creator.creatorType == "author" || creator.creatorType == "interviewer" || creator.creatorType == "inventor" || creator.creatorType == "director" || creator.creatorType == "programmer" || creator.creatorType == "artist" || creator.creatorType == "podcaster" || creator.creatorType == "presenter") { | |
author += " and " + creatorString; | |
} else if (creator.creatorType == "bookAuthor") { | |
bookauthor += " and " + creatorString; | |
} else if (creator.creatorType == "commenter") { | |
commentator += " and " + creatorString; | |
} else if (creator.creatorType == "editor") { | |
editor += " and " + creatorString; | |
} else if (creator.creatorType == "translator") { | |
translator += " and " + creatorString; | |
} else if (creator.creatorType == "seriesEditor") { //let's call them redacors | |
editorb += " and " + creatorString; | |
} else { // the rest into editora with editoratype = collaborator | |
editora += " and " + creatorString; | |
} | |
} | |
//remove first " and " string | |
if (author) { | |
writeField("author", author.substr(5), false, noEscape); | |
} | |
if (bookauthor) { | |
writeField("bookauthor", bookauthor.substr(5), false, noEscape); | |
} | |
if (commentator) { | |
writeField("commentator", commentator.substr(5), false, noEscape); | |
} | |
if (editor) { | |
writeField("editor", editor.substr(5), false, noEscape); | |
} | |
if (editora) { | |
writeField("editora", editora.substr(5), false, noEscape); | |
writeField("editoratype", "collaborator"); | |
} | |
if (editorb) { | |
writeField("editorb", editorb.substr(5), false, noEscape); | |
writeField("editorbtype", "redactor"); | |
} | |
if (holder) { | |
writeField("holder", holder.substr(5), false, noEscape); | |
} | |
if (translator) { | |
writeField("translator", translator.substr(5), false, noEscape); | |
} | |
} | |
if (item.accessDate) { | |
writeField("urldate", Zotero.Utilities.strToISO(item.accessDate)); | |
} | |
//TODO enable handling of date ranges when that's added to zotero | |
if (item.date) { | |
writeField("date", Zotero.Utilities.strToISO(item.date)); | |
} | |
//Map Languages to biblatex-field "langid" (used for | |
//hyphenation with a correct setting of the "autolang" option) | |
//if possible. See babelLanguageMap above for languagecodes to use | |
if (item.language) { | |
var langcode = item.language.match(/^([a-z]{2,3})(?:[^a-z](.+))?$/i); //not too strict | |
if (langcode){ | |
var lang = babelLanguageMap[langcode[1]]; | |
if (typeof lang == 'string') { | |
//if there are no variants for this language | |
writeField("langid", lang); | |
} else if (typeof lang == 'object') { | |
var variant = lang[langcode[2]]; | |
if (variant) { | |
writeField("langid", variant); | |
} else { | |
writeField("langid", lang[""]); //use default variant | |
} | |
} | |
} | |
} | |
if (extraFields) { | |
// Export identifiers | |
// Dedicated fields | |
for (var i=0; i<extraFields.length; i++) { | |
var rec = extraFields[i]; | |
if (!rec.field) continue; | |
if (!revExtraIds[rec.field] && !revEprintIds[rec.field]) continue; | |
var value = rec.value.trim(); | |
if (!value) continue; | |
var label; | |
if (label = revExtraIds[rec.field]) { | |
writeField(label, '{'+value+'}', true); | |
} else if (label = revEprintIds[rec.field]) { | |
writeField('eprinttype', label); | |
writeField('eprint', '{' + value + '}', true); | |
} | |
extraFields.splice(i, 1); | |
i--; | |
} | |
var extra = extraFieldsToString(extraFields); | |
if (extra && !noteused) writeField("note", extra); | |
} | |
if (item.tags && item.tags.length) { | |
var tagString = ""; | |
for (var i=0; i<item.tags.length; i++) { | |
tagString += ", " + item.tags[i].tag; | |
} | |
writeField("keywords", tagString.substr(2)); | |
} | |
if (item.notes && Zotero.getOption("exportNotes")) { | |
for (var i=0; i<item.notes.length; i++) { | |
var note = item.notes[i]; | |
writeField("annotation", Zotero.Utilities.unescapeHTML(note["note"])); | |
} | |
} | |
if (item.attachments) { | |
var attachmentString = ""; | |
for (var i=0; i<item.attachments.length; i++) { | |
var attachment = item.attachments[i]; | |
if (Zotero.getOption("exportFileData") && attachment.saveFile) { | |
attachment.saveFile(attachment.defaultPath, true); | |
attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":" | |
+ encodeFilePathComponent(attachment.defaultPath) + ":" | |
+ encodeFilePathComponent(attachment.mimeType); | |
} else if (attachment.localPath) { | |
attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":" | |
+ encodeFilePathComponent(attachment.localPath) + ":" | |
+ encodeFilePathComponent(attachment.mimeType); | |
} | |
} | |
if (attachmentString) { | |
writeField("file", attachmentString.substr(1)); | |
} | |
} | |
Zotero.write("\n}"); | |
} | |
} |