From 1f320e1f5d5fd818e2c2d532f4789e38792a77a2 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Thu, 1 Mar 2018 16:58:54 -0500 Subject: [PATCH] Be more lenient about Extra field values than citeproc-js Allow fields like "Original Date: 2018" and convert them to "original-date: 2018" when sending to citeproc-js. For reference: http://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#cheater-syntax-for-odd-fields --- chrome/content/zotero/xpcom/cite.js | 98 +++++++++++++++++++++++ chrome/content/zotero/xpcom/data/items.js | 1 + chrome/content/zotero/xpcom/utilities.js | 6 ++ test/tests/citeTest.js | 25 ++++++ 4 files changed, 130 insertions(+) create mode 100644 test/tests/citeTest.js diff --git a/chrome/content/zotero/xpcom/cite.js b/chrome/content/zotero/xpcom/cite.js index 12b016bba6..2c613e18c6 100644 --- a/chrome/content/zotero/xpcom/cite.js +++ b/chrome/content/zotero/xpcom/cite.js @@ -320,6 +320,104 @@ Zotero.Cite = { } else { return Zotero.Items.get(id); } + }, + + extraToCSL: function (extra) { + return extra.replace(/^([A-Za-z \-]+)(:\s*.+)/gm, function (_, field, value) { + var originalField = field; + var field = field.toLowerCase().replace(/ /g, '-'); + // Fields from https://aurimasv.github.io/z2csl/typeMap.xml + switch (field) { + // Standard fields + case 'abstract': + case 'accessed': + case 'annote': + case 'archive': + case 'archive-place': + case 'author': + case 'authority': + case 'call-number': + case 'chapter-number': + case 'citation-label': + case 'citation-number': + case 'collection-editor': + case 'collection-number': + case 'collection-title': + case 'composer': + case 'container': + case 'container-author': + case 'container-title': + case 'container-title-short': + case 'dimensions': + case 'director': + case 'edition': + case 'editor': + case 'editorial-director': + case 'event': + case 'event-date': + case 'event-place': + case 'first-reference-note-number': + case 'genre': + case 'illustrator': + case 'interviewer': + case 'issue': + case 'issued': + case 'jurisdiction': + case 'keyword': + case 'language': + case 'locator': + case 'medium': + case 'note': + case 'number': + case 'number-of-pages': + case 'number-of-volumes': + case 'original-author': + case 'original-date': + case 'original-publisher': + case 'original-publisher-place': + case 'original-title': + case 'page': + case 'page-first': + case 'publisher': + case 'publisher-place': + case 'recipient': + case 'references': + case 'reviewed-author': + case 'reviewed-title': + case 'scale': + case 'section': + case 'source': + case 'status': + case 'submitted': + case 'title': + case 'title-short': + case 'translator': + case 'version': + case 'volume': + case 'year-suffix': + break; + + // Uppercase fields + case 'doi': + case 'isbn': + case 'issn': + case 'pmcid': + case 'pmid': + case 'url': + field = field.toUpperCase(); + break; + + // Weirdo + case 'archive-location': + field = 'archive_location'; + break; + + // Don't change other lines + default: + field = originalField; + } + return field + value; + }); } }; diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index 4bd91ee933..122df1edaf 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -1445,6 +1445,7 @@ Zotero.Items = function() { return title.replace(/^[\[\'\"](.*)[\'\"\]]?$/, '$1') } + Zotero.DataObjects.call(this); return this; diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 22cd667106..8a14685132 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1581,6 +1581,9 @@ Zotero.Utilities = { var isbn = value.match(/^(?:97[89]-?)?(?:\d-?){9}[\dx](?!-)\b/i); if (isbn) value = isbn[0]; } + else if (field == 'extra') { + value = Zotero.Cite.extraToCSL(value); + } // Strip enclosing quotes if(value.charAt(0) == '"' && value.indexOf('"', 1) == value.length - 1) { @@ -1753,6 +1756,9 @@ Zotero.Utilities = { } if(Zotero.ItemFields.isValidForType(fieldID, itemTypeID)) { + // TODO: Convert restrictive Extra cheater syntax ('original-date: 2018') + // to nicer format we allow ('Original Date: 2018'), unless we've added + // those fields before we get to that if(isZoteroItem) { item.setField(fieldID, cslItem[variable]); } else { diff --git a/test/tests/citeTest.js b/test/tests/citeTest.js new file mode 100644 index 0000000000..a02a421af9 --- /dev/null +++ b/test/tests/citeTest.js @@ -0,0 +1,25 @@ +describe("Zotero.Cite", function () { + describe("#extraToCSL()", function () { + it("should convert Extra field values to the more restrictive citeproc-js cheater syntax", function () { + var str1 = 'Original Date: 2017\n' // uppercase/spaces converted to lowercase/hyphens + + 'Archive-Place: New York\n' // allow hyphen even with title case + + 'Container title: Title\n' // mixed case + + 'DOI: 10.0/abc\n' // certain fields are uppercase + + 'Archive Location: Foo\n' // requires an underscore + + 'Original Publisher Place: London, UK\n' // extra space OK + + '\n\n' + + "Ignore other strings: they're not fields\n" + + 'This is just some text.' + var str2 = 'original-date: 2017\n' + + 'archive-place: New York\n' + + 'container-title: Title\n' + + 'DOI: 10.0/abc\n' + + 'archive_location: Foo\n' + + 'original-publisher-place: London, UK\n' + + '\n\n' + + "Ignore other strings: they're not fields\n" + + 'This is just some text.'; + assert.equal(Zotero.Cite.extraToCSL(str1), str2); + }); + }); +});