PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/BibLaTeX.js

https://gitlab.com/mba811/translators
JavaScript | 769 lines | 659 code | 63 blank | 47 comment | 207 complexity | d5f3186fe0aed3d7673e303aa2b2f782 MD5 | raw file
  1. {
  2. "translatorID": "b6e39b57-8942-4d11-8259-342c46ce395f",
  3. "translatorType": 2,
  4. "label": "BibLaTeX",
  5. "creator": "Simon Kornblith, Richard Karnesky and Anders Johansson",
  6. "target": "bib",
  7. "minVersion": "2.1.9",
  8. "maxVersion": "null",
  9. "priority": 100,
  10. "inRepository": true,
  11. "configOptions":{"getCollections": true},
  12. "displayOptions": {
  13. "exportCharset": "UTF-8",
  14. "exportNotes": false,
  15. "exportFileData": false,
  16. "useJournalAbbreviation": false
  17. },
  18. "lastUpdated": "2014-06-23 05:03:43"
  19. }
  20. //%a = first listed creator surname
  21. //%y = year
  22. //%t = first word of title
  23. var citeKeyFormat = "%a_%t_%y";
  24. var fieldMap = {
  25. location: "place",
  26. chapter: "chapter",
  27. edition: "edition",
  28. title: "title",
  29. volume: "volume",
  30. rights: "rights", //it's rights in zotero nowadays
  31. isbn: "ISBN",
  32. issn: "ISSN",
  33. url: "url",
  34. doi: "DOI",
  35. series: "series",
  36. shorttitle: "shortTitle",
  37. abstract: "abstractNote",
  38. volumes: "numberOfVolumes",
  39. version: "version",
  40. eventtitle: "conferenceName",
  41. pages: "pages",
  42. pagetotal: "numPages"
  43. };
  44. //more conversions done below with special rules
  45. /**
  46. * Identifiers from item.extra
  47. * Copied from BibTeX
  48. */
  49. // Exported in BibTeX and BibLaTeX
  50. var revExtraIds = {
  51. LCCN: 'lccn',
  52. MR: 'mrnumber',
  53. Zbl: 'zmnumber',
  54. PMCID: 'pmcid',
  55. PMID: 'pmid'
  56. };
  57. // Imported by BibTeX. Exported by BibLaTeX only
  58. var revEprintIds = {
  59. // eprinttype: Zotero label
  60. // From BibLaTeX manual
  61. arXiv: 'arxiv', // Sorry, but no support for eprintclass yet
  62. JSTOR: 'jstor',
  63. //PMID: 'pubmed', // Not sure if we should do this instead
  64. HDL: 'hdl',
  65. GoogleBooksID: 'googlebooks'
  66. }
  67. function parseExtraFields(extra) {
  68. var lines = extra.split(/[\r\n]+/);
  69. var fields = [];
  70. for(var i=0; i<lines.length; i++) {
  71. var rec = { raw: lines[i] };
  72. var line = lines[i].trim();
  73. var splitAt = line.indexOf(':');
  74. if(splitAt > 1) {
  75. rec.field = line.substr(0,splitAt).trim();
  76. rec.value = line.substr(splitAt + 1).trim();
  77. }
  78. fields.push(rec);
  79. }
  80. return fields;
  81. }
  82. function extraFieldsToString(extra) {
  83. var str = '';
  84. for(var i=0; i<extra.length; i++) {
  85. if(!extra[i].raw) {
  86. str += '\n' + extra[i].field + ': ' + extra[i].value;
  87. } else {
  88. str += '\n' + extra[i].raw;
  89. }
  90. }
  91. return str.substr(1);
  92. }
  93. //POTENTIAL ISSUES
  94. //accessDate:"accessDate", //only written on attached webpage snapshots by zotero
  95. var zotero2biblatexTypeMap = {
  96. "book": "book",
  97. "bookSection": "incollection",
  98. "journalArticle": "article",
  99. "magazineArticle": "article",
  100. "newspaperArticle": "article",
  101. "thesis": "thesis",
  102. "letter": "letter",
  103. "manuscript": "unpublished",
  104. "interview": "misc",
  105. "film": "movie",
  106. "artwork": "artwork",
  107. "webpage": "online",
  108. "conferencePaper": "inproceedings",
  109. "report": "report",
  110. "bill": "legislation",
  111. "case": "jurisdiction",
  112. "hearing": "jurisdiction",
  113. "patent": "patent",
  114. "statute": "legislation",
  115. "email": "letter",
  116. "map": "misc",
  117. "blogPost": "online",
  118. "instantMessage": "misc",
  119. "forumPost": "online",
  120. "audioRecording": "audio",
  121. "presentation": "unpublished",
  122. "videoRecording": "video",
  123. "tvBroadcast": "misc",
  124. "radioBroadcast": "misc",
  125. "podcast": "audio",
  126. "computerProgram": "software",
  127. "document": "misc",
  128. "encyclopediaArticle": "inreference",
  129. "dictionaryEntry": "inreference"
  130. };
  131. var alwaysMap = {
  132. "|": "{\\textbar}",
  133. "<": "{\\textless}",
  134. ">": "{\\textgreater}",
  135. "~": "{\\textasciitilde}",
  136. "^": "{\\textasciicircum}",
  137. "\\": "{\\textbackslash}",
  138. "{": "\\{",
  139. "}": "\\}"
  140. };
  141. //to map ISO language codes (tries to follow IETF RFC5646) to babel
  142. //language codes used in biblatex. Taken from Babel manual 3.9h.
  143. var babelLanguageMap = {
  144. "af": "afrikaans",
  145. "ar": "arabic",
  146. //bahasa (see malay and indonesian)
  147. "eu": "basque",
  148. "br": "breton",
  149. "bg": "bulgarian",
  150. "ca": "catalan",
  151. "hr": "croatian",
  152. "cz": "czech",
  153. "da": "danish",
  154. "nl": "dutch",
  155. "en": {
  156. "": "english", //same as american
  157. "US": "american",
  158. "GB": "british",
  159. "CA": "canadian",
  160. "AU": "australian",
  161. "NZ": "newzealand"
  162. },
  163. "eo": "esperanto",
  164. "et": "estonian",
  165. //ethiop (package for many languages)
  166. "fa": "farsi",
  167. "fi": "finnish",
  168. "fr": {
  169. "": "french",
  170. "CA": "canadien"
  171. //frenchle (a special package)
  172. },
  173. "fur": "friulan",
  174. "gl": "galician",
  175. "de": {
  176. "": "german",
  177. "AT": "austrian",
  178. "DE-1996": "ngerman", //these are valid IETF language codes
  179. "AT-1996": "naustrian",
  180. "1996": "ngerman"
  181. },
  182. "el": {
  183. "": "greek",
  184. "polyton": "polutonikogreek"
  185. },
  186. "he": "hebrew",
  187. "hi": "hindi",
  188. "is": "icelandic",
  189. "id": "indonesian", //aliases: bahasai, indon
  190. "ia": "interlingua",
  191. "ga": "irish",
  192. "it": "italian",
  193. "ja": "japanese",
  194. "la": "latin",
  195. "lv": "latvian",
  196. "lt": "lithuanian",
  197. "dsb": "lowersorbian",
  198. "hu": "magyar",
  199. "zlm": "malay", //aliases: bahasam, melayu (currently, there's no
  200. //real difference between bahasam and bahasai in babel)
  201. "mn": "mongolian",
  202. "se": "samin",
  203. "nn": "nynorsk", //nynorsk
  204. "nb": "norsk", //bokmål
  205. "no": "norwegian", //"no" could be used, norwegian is an alias for "norsk" in babel
  206. "zh": {
  207. "": "pinyin", //only supported chinese in babel is the romanization pinyin?
  208. "Latn": "pinyin"
  209. },
  210. "pl": "polish",
  211. "pt": {
  212. "": "portuguese",
  213. "PT": "portuguese",
  214. "BR": "brazil"
  215. },
  216. "ro": "romanian",
  217. "rm": "romansh",
  218. "ru": "russian",
  219. "gd": "scottish",
  220. "sr": {
  221. "": "serbian", //latin script as default?
  222. "Cyrl": "serbianc",
  223. "Latn": "serbian",
  224. },
  225. "sk": "slovak",
  226. "sl": "slovene",
  227. //spanglish (pseudo language)
  228. "es": "spanish",
  229. "sv": "swedish",
  230. "th": "thaicjk", //thaicjk preferred?
  231. "tr": "turkish",
  232. "tk": "turkmen",
  233. "uk": "ukrainian",
  234. "hsb": "uppersorbian",
  235. "vi": "vietnamese",
  236. "cy": "welsh",
  237. };
  238. // some fields are, in fact, macros. If that is the case then we should not put the
  239. // data in the braces as it will cause the macros to not expand properly
  240. function writeField(field, value, isMacro, noEscape) {
  241. if (!value && typeof value != "number") return;
  242. value = value + ""; // convert integers to strings
  243. Zotero.write(",\n\t" + field + " = ");
  244. if (!isMacro) Zotero.write("{");
  245. // url field is preserved, for use with \href and \url
  246. // Other fields (DOI?) may need similar treatment
  247. if (!noEscape && !isMacro && !(field == "url" || field == "doi" || field == "file" || field == "lccn")) {
  248. //var titleCase = isTitleCase(value); //figure this out before escaping all the characters
  249. // I hope these are all the escape characters! (except for < > which are handled later)
  250. value = value.replace(/[|\~\^\\\{\}]/g, mapEscape).replace(/[\#\$\%\&\_]/g, "\\$&");
  251. //convert the HTML markup allowed in Zotero for rich text to TeX
  252. value = mapHTMLmarkup(value);
  253. //escape < > if mapHTMLmarkup did not convert some
  254. value = value.replace(/[<>]/g, mapEscape);
  255. // Case of words with uppercase characters in non-initial positions is preserved with braces.
  256. // we're looking at all unicode letters
  257. var protectCaps = new ZU.XRegExp("\\b\\p{Letter}+\\p{Uppercase_Letter}\\p{Letter}*", 'g')
  258. if (field != "pages") {
  259. value = ZU.XRegExp.replace(value, protectCaps, "{$0}");
  260. }
  261. }
  262. //we write utf8
  263. //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;
  264. if (!((field == "url") || (field == "doi") || (field == "file"))) value = mapHTMLmarkup(value);
  265. Zotero.write(value);
  266. if (!isMacro) Zotero.write("}");
  267. }
  268. function mapHTMLmarkup(characters) {
  269. //converts the HTML markup allowed in Zotero for rich text to TeX
  270. //since < and > have already been escaped, we need this rather hideous code - I couldn't see a way around it though.
  271. //italics and bold
  272. 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}");
  273. //sub and superscript
  274. 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}}\$");
  275. //two variants of small caps
  276. 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}");
  277. return characters;
  278. }
  279. function mapEscape(character) {
  280. return alwaysMap[character];
  281. }
  282. // a little substitution function for BibTeX keys, where we don't want LaTeX
  283. // escaping, but we do want to preserve the base characters
  284. function tidyAccents(s) {
  285. var r = s.toLowerCase();
  286. // XXX Remove conditional when we drop Zotero 2.1.x support
  287. // This is supported in Zotero 3.0 and higher
  288. if (ZU.removeDiacritics !== undefined)
  289. r = ZU.removeDiacritics(r, true);
  290. else {
  291. // We fall back on the replacement list we used previously
  292. r = r.replace(new RegExp("[ä]", 'g'), "ae");
  293. r = r.replace(new RegExp("[ö]", 'g'), "oe");
  294. r = r.replace(new RegExp("[ü]", 'g'), "ue");
  295. r = r.replace(new RegExp("[àáâãå]", 'g'), "a");
  296. r = r.replace(new RegExp("æ", 'g'), "ae");
  297. r = r.replace(new RegExp("ç", 'g'), "c");
  298. r = r.replace(new RegExp("[èéêë]", 'g'), "e");
  299. r = r.replace(new RegExp("[ìíîï]", 'g'), "i");
  300. r = r.replace(new RegExp("ñ", 'g'), "n");
  301. r = r.replace(new RegExp("[òóôõ]", 'g'), "o");
  302. r = r.replace(new RegExp("œ", 'g'), "oe");
  303. r = r.replace(new RegExp("[ùúû]", 'g'), "u");
  304. r = r.replace(new RegExp("[ýÿ]", 'g'), "y");
  305. }
  306. return r;
  307. };
  308. var numberRe = /^[0-9]+/;
  309. // Below is a list of words that should not appear as part of the citation key
  310. // in includes the indefinite articles of English, German, French and Spanish, as well as a small set of English prepositions whose
  311. // force is more grammatical than lexical, i.e. which are likely to strike many as 'insignificant'.
  312. // The assumption is that most who want a title word in their key would prefer the first word of significance.
  313. 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)/g;
  314. var citeKeyConversionsRe = /%([a-zA-Z])/;
  315. var citeKeyCleanRe = /[^a-z0-9\!\$\&\*\+\-\.\/\:\;\<\>\?\[\]\^\_\`\|]+/g;
  316. var citeKeyConversions = {
  317. "a": function (flags, item) {
  318. if (item.creators && item.creators[0] && item.creators[0].lastName) {
  319. return item.creators[0].lastName.toLowerCase().replace(/ /g, "_").replace(/,/g, "");
  320. }
  321. return "";
  322. },
  323. "t": function (flags, item) {
  324. if (item["title"]) {
  325. return item["title"].toLowerCase().replace(citeKeyTitleBannedRe, "").split(/\s+/g)[0];
  326. }
  327. return "";
  328. },
  329. "y": function (flags, item) {
  330. if (item.date) {
  331. var date = Zotero.Utilities.strToDate(item.date);
  332. if (date.year && numberRe.test(date.year)) {
  333. return date.year;
  334. }
  335. }
  336. return "????";
  337. }
  338. }
  339. //checks whether an item contains any creator of type ctype
  340. function creatorCheck(item, ctype) {
  341. if (item.creators && item.creators.length) {
  342. for (var i=0; i<item.creators.length; i++) {
  343. if (item.creators[i].creatorType == ctype) {
  344. return true; //found a ctype creator
  345. }
  346. }
  347. }
  348. //didn't find any ctype creator (or no creators at all)
  349. return false;
  350. }
  351. function buildCiteKey(item, citekeys) {
  352. var basekey = "";
  353. var counter = 0;
  354. citeKeyFormatRemaining = citeKeyFormat;
  355. while (citeKeyConversionsRe.test(citeKeyFormatRemaining)) {
  356. if (counter > 100) {
  357. Zotero.debug("Pathological BibTeX format: " + citeKeyFormat);
  358. break;
  359. }
  360. var m = citeKeyFormatRemaining.match(citeKeyConversionsRe);
  361. if (m.index > 0) {
  362. //add data before the conversion match to basekey
  363. basekey = basekey + citeKeyFormatRemaining.substr(0, m.index);
  364. }
  365. var flags = ""; // for now
  366. var f = citeKeyConversions[m[1]];
  367. if (typeof (f) == "function") {
  368. var value = f(flags, item);
  369. Zotero.debug("Got value " + value + " for %" + m[1]);
  370. //add conversion to basekey
  371. basekey = basekey + value;
  372. }
  373. citeKeyFormatRemaining = citeKeyFormatRemaining.substr(m.index + m.length);
  374. counter++;
  375. }
  376. if (citeKeyFormatRemaining.length > 0) {
  377. basekey = basekey + citeKeyFormatRemaining;
  378. }
  379. // for now, remove any characters not explicitly known to be allowed;
  380. // we might want to allow UTF-8 citation keys in the future, depending
  381. // on implementation support.
  382. //
  383. // no matter what, we want to make sure we exclude
  384. // " # % ' ( ) , = { } ~ and backslash
  385. // however, we want to keep the base characters
  386. basekey = tidyAccents(basekey);
  387. basekey = basekey.replace(citeKeyCleanRe, "");
  388. var citekey = basekey;
  389. var i = 0;
  390. while (citekeys[citekey]) {
  391. i++;
  392. citekey = basekey + "-" + i;
  393. }
  394. citekeys[citekey] = true;
  395. return citekey;
  396. }
  397. var filePathSpecialChars = '\\\\:;{}$'; // $ for Mendeley
  398. var encodeFilePathRE = new RegExp('[' + filePathSpecialChars + ']', 'g');
  399. function encodeFilePathComponent(value) {
  400. return value.replace(encodeFilePathRE, "\\$&");
  401. }
  402. function doExport() {
  403. //Zotero.write("% biblatex export generated by Zotero "+Zotero.Utilities.getVersion());
  404. // to make sure the BOM gets ignored
  405. Zotero.write("\n");
  406. var first = true;
  407. var citekeys = new Object();
  408. var item;
  409. while (item = Zotero.nextItem()) {
  410. //don't export standalone notes and attachments
  411. if (item.itemType == "note" || item.itemType == "attachment") continue;
  412. var noteused = false; //a switch for keeping track whether the
  413. //field "note" has been written to
  414. // determine type
  415. var type = zotero2biblatexTypeMap[item.itemType];
  416. if (typeof (type) == "function") {
  417. type = type(item);
  418. }
  419. //inbook is reasonable at times, using a bookauthor should
  420. //indicate this
  421. if(item.itemType == "bookSection" &&
  422. creatorCheck(item, "bookAuthor")) type = "inbook";
  423. //a book without author but with editors is a collection
  424. if(item.itemType == "book" && !creatorCheck(item,"author") &&
  425. creatorCheck(item, "editor")) type = "collection";
  426. //biblatex recommends us to use mvbook for multi-volume books
  427. if (type == "book" && item.volume) type = "mvbook"
  428. if (!type) type = "misc";
  429. var citekey = "";
  430. if (!citekey) {
  431. // create a unique citation key
  432. citekey = buildCiteKey(item, citekeys);
  433. }
  434. // write citation key (removed the comma)
  435. Zotero.write((first ? "" : "\n\n") + "@" + type + "{" + citekey);
  436. first = false;
  437. for (var field in fieldMap) {
  438. if (item[fieldMap[field]]) {
  439. writeField(field, item[fieldMap[field]]);
  440. }
  441. }
  442. // Fields needing special treatment and not easily translatable via fieldMap
  443. //e.g. where fieldname translation is dependent upon type, or special transformations
  444. //has to be made
  445. //all kinds of numbers
  446. if (item.reportNumber || item.seriesNumber || item.patentNumber || item.billNumber || item.episodeNumber || item.number) {
  447. writeField("number", item.reportNumber || item.seriesNumber || item.patentNumber || item.billNumber || item.episodeNumber || item.number);
  448. }
  449. //split numeric and nonnumeric issue specifications (for journals) into "number" and "issue"
  450. if (item.issue) { //issue
  451. var jnumber = parseInt(item.issue);
  452. if (!isNaN(jnumber)) {
  453. writeField("number", jnumber);
  454. } else {
  455. writeField("issue", item.issue);
  456. }
  457. }
  458. //publicationTitles and special titles
  459. if (item.publicationTitle) {
  460. if (item.itemType == "bookSection" || item.itemType == "conferencePaper" || item.itemType == "dictionaryEntry" || item.itemType == "encyclopediaArticle") {
  461. writeField("booktitle", item.publicationTitle);
  462. } else if (item.itemType == "magazineArticle" || item.itemType == "newspaperArticle") {
  463. writeField("journaltitle", item.publicationTitle);
  464. } else if (item.itemType == "journalArticle") {
  465. if (Zotero.getOption("useJournalAbbreviation")) {
  466. writeField("journaltitle", item.journalAbbreviation);
  467. } else {
  468. writeField("journaltitle", item.publicationTitle);
  469. writeField("shortjournal", item.journalAbbreviation);
  470. }
  471. }
  472. }
  473. if (item.websiteTitle || item.forumTitle || item.blogTitle || item.programTitle) {
  474. writeField("titleaddon", item.websiteTitle || item.forumTitle || item.blogTitle || item.programTitle);
  475. }
  476. //publishers
  477. if (item.publisher) {
  478. if (item.itemType == "thesis" || item.itemType == "report") {
  479. writeField("institution", item.publisher);
  480. } else {
  481. writeField("publisher", item.publisher);
  482. }
  483. }
  484. //things concerning "type"
  485. if (item.itemType == "letter") {
  486. if (item.letterType) {
  487. writeField("type", item.letterType);
  488. } else {
  489. writeField("type", "Letter"); //this isn't optimal, perhaps later versions of biblatex will add some suitable localization key
  490. }
  491. } else if (item.itemType == "email") {
  492. writeField("type", "E-mail");
  493. } else if (item.itemType == "thesis" &&
  494. (!item.thesisType || item.thesisType.search(/ph\.?d/i) != -1)) {
  495. writeField("type", "phdthesis");
  496. } else if (item.manuscriptType || item.thesisType || item.websiteType || item.presentationType || item.reportType || item.mapType) {
  497. writeField("type", item.manuscriptType || item.thesisType || item.websiteType || item.presentationType || item.reportType || item.mapType);
  498. }
  499. if (item.presentationType || item.manuscriptType) {
  500. writeField("howpublished", item.presentationType || item.manuscriptType);
  501. }
  502. //case of specific eprint-archives in archive-fields
  503. if (item.archive && item.archiveLocation) {
  504. if (item.archive == "arXiv" || item.archive == "arxiv") {
  505. writeField("eprinttype", "arxiv");
  506. writeField("eprint", item.archiveLocation);
  507. if (item.callNumber) { //assume call number is used for arxiv class
  508. writeField("eprintclass", item.callNumber)
  509. }
  510. } else if (item.archive = "JSTOR" || item.archive == "jstor") {
  511. writeField("eprinttype", "jstor");
  512. writeField("eprint", item.archiveLocation);
  513. } else if (item.archive = "PubMed" || item.archive == "pubmed") {
  514. writeField("eprinttype", "pubmed");
  515. writeField("eprint", item.archiveLocation);
  516. } else if (item.archive = "HDL" || item.archive == "hdl") {
  517. writeField("eprinttype", "hdl");
  518. writeField("eprint", item.archiveLocation);
  519. } else if (item.archive = "googlebooks" || item.archive == "Google Books") {
  520. writeField("eprinttype", "googlebooks");
  521. writeField("eprint", item.archiveLocation);
  522. }
  523. }
  524. //presentations have a meetingName field which we want to
  525. //map to note
  526. if (item.meetingName) {
  527. writeField("note", item.meetingName);
  528. noteused = true;
  529. }
  530. if (item.creators && item.creators.length) {
  531. // split creators into subcategories
  532. var author = "";
  533. var bookauthor = "";
  534. var commentator = "";
  535. var editor = "";
  536. var editora = "";
  537. var editorb = "";
  538. var holder = "";
  539. var translator = "";
  540. var noEscape = false;
  541. for (var i=0; i<item.creators.length; i++) {
  542. var creator = item.creators[i];
  543. var creatorString;
  544. if (creator.firstName) {
  545. var fname = creator.firstName.split(/\s*,!?\s*/);
  546. fname.push(fname.shift()); // If we have a Jr. part(s), it should precede first name
  547. creatorString = creator.lastName + ", " + fname.join(', ');
  548. } else {
  549. creatorString = creator.lastName;
  550. }
  551. creatorString = creatorString.replace(/[|\<\>\~\^\\\{\}]/g, mapEscape)
  552. .replace(/([\#\$\%\&\_])/g, "\\$1");
  553. if (creator.fieldMode == true) { // fieldMode true, assume corporate author
  554. creatorString = "{" + creatorString + "}";
  555. noEscape = true;
  556. } else {
  557. creatorString = creatorString.replace(/ (and) /gi, ' {$1} ');
  558. }
  559. if (creator.creatorType == "author" || creator.creatorType == "interviewer" || creator.creatorType == "director" || creator.creatorType == "programmer" || creator.creatorType == "artist" || creator.creatorType == "podcaster" || creator.creatorType == "presenter") {
  560. author += " and " + creatorString;
  561. } else if (creator.creatorType == "bookAuthor") {
  562. bookauthor += " and " + creatorString;
  563. } else if (creator.creatorType == "commenter") {
  564. commentator += " and " + creatorString;
  565. } else if (creator.creatorType == "editor") {
  566. editor += " and " + creatorString;
  567. } else if (creator.creatorType == "inventor") {
  568. holder += " and " + creatorString;
  569. } else if (creator.creatorType == "translator") {
  570. translator += " and " + creatorString;
  571. } else if (creator.creatorType == "seriesEditor") { //let's call them redacors
  572. editorb += " and " + creatorString;
  573. } else { // the rest into editora with editoratype = collaborator
  574. editora += " and " + creatorString;
  575. }
  576. }
  577. //remove first " and " string
  578. if (author) {
  579. writeField("author", author.substr(5), false, noEscape);
  580. }
  581. if (bookauthor) {
  582. writeField("bookauthor", bookauthor.substr(5), false, noEscape);
  583. }
  584. if (commentator) {
  585. writeField("commentator", commenter.substr(5), false, noEscape);
  586. }
  587. if (editor) {
  588. writeField("editor", editor.substr(5), false, noEscape);
  589. }
  590. if (editora) {
  591. writeField("editora", editora.substr(5), false, noEscape);
  592. writeField("editoratype", "collaborator");
  593. }
  594. if (editorb) {
  595. writeField("editorb", editorb.substr(5), false, noEscape);
  596. writeField("editorbtype", "redactor");
  597. }
  598. if (holder) {
  599. writeField("holder", holder.substr(5), false, noEscape);
  600. }
  601. if (translator) {
  602. writeField("translator", translator.substr(5), false, noEscape);
  603. }
  604. }
  605. if (item.accessDate) {
  606. writeField("urldate", Zotero.Utilities.strToISO(item.accessDate));
  607. }
  608. //TODO enable handling of date ranges when that's added to zotero
  609. if (item.date) {
  610. writeField("date", Zotero.Utilities.strToISO(item.date));
  611. }
  612. //Map Languages to biblatex-field "langid" (used for
  613. //hyphenation with a correct setting of the "autolang" option)
  614. //if possible. See babelLanguageMap above for languagecodes to use
  615. if (item.language) {
  616. var langcode = item.language.match(/^([a-z]{2,3})(?:[^a-z](.+))?$/i); //not too strict
  617. if(langcode){
  618. var lang = babelLanguageMap[langcode[1]];
  619. if (typeof lang == 'string') {
  620. //if there are no variants for this language
  621. writeField("langid", lang);
  622. } else if (typeof lang == 'object') {
  623. var variant = lang[langcode[2]];
  624. if (variant) {
  625. writeField("langid", variant);
  626. } else {
  627. writeField("langid", lang[""]); //use default variant
  628. }
  629. }
  630. }
  631. }
  632. if(item.extra) {
  633. // Export identifiers
  634. var extraFields = parseExtraFields(item.extra);
  635. // Dedicated fields
  636. for(var i=0; i<extraFields.length; i++) {
  637. var rec = extraFields[i];
  638. if(!rec.field) continue;
  639. if(!revExtraIds[rec.field] && !revEprintIds[rec.field]) continue;
  640. var value = rec.value.trim();
  641. if(!value) continue;
  642. var label;
  643. if(label = revExtraIds[rec.field]) {
  644. writeField(label, '{'+value+'}', true);
  645. } else if (label = revEprintIds[rec.field]) {
  646. writeField('eprinttype', label);
  647. writeField('eprint', '{' + value + '}', true);
  648. }
  649. extraFields.splice(i, 1);
  650. i--;
  651. }
  652. var extra = extraFieldsToString(extraFields);
  653. if(extra && !noteused) writeField("note", extra);
  654. }
  655. if (item.tags && item.tags.length) {
  656. var tagString = "";
  657. for (var i=0; i<item.tags.length; i++) {
  658. tagString += ", " + item.tags[i].tag;
  659. }
  660. writeField("keywords", tagString.substr(2));
  661. }
  662. if (item.notes && Zotero.getOption("exportNotes")) {
  663. for (var i=0; i<item.notes.length; i++) {
  664. var note = item.notes[i];
  665. writeField("annotation", Zotero.Utilities.unescapeHTML(note["note"]));
  666. }
  667. }
  668. if (item.attachments) {
  669. var attachmentString = "";
  670. for (var i=0; i<item.attachments.length; i++) {
  671. var attachment = item.attachments[i];
  672. if (Zotero.getOption("exportFileData") && attachment.saveFile) {
  673. attachment.saveFile(attachment.defaultPath, true);
  674. attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":"
  675. + encodeFilePathComponent(attachment.defaultPath) + ":"
  676. + encodeFilePathComponent(attachment.mimeType);
  677. } else if (attachment.localPath) {
  678. attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":"
  679. + encodeFilePathComponent(attachment.localPath) + ":"
  680. + encodeFilePathComponent(attachment.mimeType);
  681. }
  682. }
  683. if (attachmentString) {
  684. writeField("file", attachmentString.substr(1));
  685. }
  686. }
  687. Zotero.write("\n}");
  688. }
  689. }