From 0fbae77456a74ff5b4503b863a36fe231f43ba15 Mon Sep 17 00:00:00 2001 From: Aurimas Vinckevicius Date: Mon, 3 Aug 2015 16:15:24 -0500 Subject: [PATCH 1/4] Don't use for-in to iterate over arrays in itemFromCSLJSON --- chrome/content/zotero/xpcom/utilities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 23ec452f1b..ef161a1935 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1667,7 +1667,7 @@ Zotero.Utilities = { for(var variable in CSL_TEXT_MAPPINGS) { if(variable in cslItem) { var textMappings = CSL_TEXT_MAPPINGS[variable]; - for(var i in textMappings) { + for(var i=0; i Date: Tue, 4 Aug 2015 14:19:39 -0500 Subject: [PATCH 2/4] Fix season export in CSL JSON --- chrome/content/zotero/xpcom/date.js | 4 +++- chrome/content/zotero/xpcom/utilities.js | 2 +- test/tests/data/citeProcJSExport.js | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/chrome/content/zotero/xpcom/date.js b/chrome/content/zotero/xpcom/date.js index c41b5eec50..d34c326a33 100644 --- a/chrome/content/zotero/xpcom/date.js +++ b/chrome/content/zotero/xpcom/date.js @@ -330,6 +330,8 @@ Zotero.Date = new function(){ } if(date.month) date.month--; // subtract one for JS style + else delete date.month; + Zotero.debug("DATE: retrieved with algorithms: "+JSON.stringify(date)); parts.push( @@ -369,7 +371,7 @@ Zotero.Date = new function(){ } // MONTH - if(!date.month) { + if(date.month === undefined) { // compile month regular expression var months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']; diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index ef161a1935..e24ece3a49 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1611,7 +1611,7 @@ Zotero.Utilities = { cslItem[variable] = {"date-parts":[dateParts]}; // if no month, use season as month - if(dateObj.part && !dateObj.month) { + if(dateObj.part && dateObj.month === undefined) { cslItem[variable].season = dateObj.part; } } else { diff --git a/test/tests/data/citeProcJSExport.js b/test/tests/data/citeProcJSExport.js index 3678e99098..67cb3f87ff 100644 --- a/test/tests/data/citeProcJSExport.js +++ b/test/tests/data/citeProcJSExport.js @@ -1347,8 +1347,7 @@ 1, 2 ] - ], - "season": "2000-01-02" + ] }, "title": "Title", "type": "patent" From c4cd7ce3e0a54ceaf6221d0310aeac3afa2c5e9b Mon Sep 17 00:00:00 2001 From: Aurimas Vinckevicius Date: Tue, 4 Aug 2015 15:19:33 -0500 Subject: [PATCH 3/4] Fix import of computerProgram exported as CSL JSON --- chrome/content/zotero/xpcom/utilities.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index e24ece3a49..6df5094167 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -1668,8 +1668,13 @@ Zotero.Utilities = { if(variable in cslItem) { var textMappings = CSL_TEXT_MAPPINGS[variable]; for(var i=0; i Date: Tue, 4 Aug 2015 15:22:35 -0500 Subject: [PATCH 4/4] Add tests for itemFromCSLJSON and make sure data round-trips --- chrome/content/zotero/xpcom/utilities.js | 45 +++++++++++++++--- test/tests/utilities.js | 60 +++++++++++++++++++++++- 2 files changed, 98 insertions(+), 7 deletions(-) diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index 6df5094167..18fae8927b 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -99,6 +99,7 @@ const CSL_DATE_MAPPINGS = { /* * Mappings for types + * Also see itemFromCSLJSON */ const CSL_TYPE_MAPPINGS = { 'book':"book", @@ -1645,14 +1646,44 @@ Zotero.Utilities = { * @param {Object} cslItem */ "itemFromCSLJSON":function(item, cslItem) { - var isZoteroItem = item instanceof Zotero.Item, zoteroType; + var isZoteroItem = item instanceof Zotero.Item, + zoteroType; - for(var type in CSL_TYPE_MAPPINGS) { - if(CSL_TYPE_MAPPINGS[type] == cslItem.type) { - zoteroType = type; - break; + // Some special cases to help us map item types correctly + // This ensures that we don't lose data on import. The fields + // we check are incompatible with the alternative item types + if (cslItem.type == 'book') { + zoteroType = 'book'; + if (cslItem.version) { + zoteroType = 'computerProgram'; + } + } else if (cslItem.type == 'bill') { + zoteroType = 'bill'; + if (cslItem.publisher || cslItem['number-of-volumes']) { + zoteroType = 'hearing'; + } + } else if (cslItem.type == 'song') { + zoteroType = 'audioRecording'; + if (cslItem.number) { + zoteroType = 'podcast'; + } + } else if (cslItem.type == 'motion_picture') { + zoteroType = 'film'; + if (cslItem['collection-title'] || cslItem['publisher-place'] + || cslItem['event-place'] || cslItem.volume + || cslItem['number-of-volumes'] || cslItem.ISBN + ) { + zoteroType = 'videoRecording'; + } + } else { + for(var type in CSL_TYPE_MAPPINGS) { + if(CSL_TYPE_MAPPINGS[type] == cslItem.type) { + zoteroType = type; + break; + } } } + if(!zoteroType) zoteroType = "document"; var itemTypeID = Zotero.ItemTypes.getID(zoteroType); @@ -1682,10 +1713,12 @@ Zotero.Utilities = { if(Zotero.ItemFields.isValidForType(fieldID, itemTypeID)) { if(isZoteroItem) { - item.setField(fieldID, cslItem[variable], true); + item.setField(fieldID, cslItem[variable]); } else { item[field] = cslItem[variable]; } + + break; } } } diff --git a/test/tests/utilities.js b/test/tests/utilities.js index 299a3fbb59..776b744a04 100644 --- a/test/tests/utilities.js +++ b/test/tests/utilities.js @@ -221,7 +221,7 @@ describe("Zotero.Utilities", function() { attachment.save(); - cslJSONAttachment = Zotero.Utilities.itemToCSLJSON(attachment); + let cslJSONAttachment = Zotero.Utilities.itemToCSLJSON(attachment); assert.equal(cslJSONAttachment.type, 'article', 'attachment is exported as "article"'); assert.equal(cslJSONAttachment.title, 'Empty', 'attachment title is correct'); assert.deepEqual(cslJSONAttachment.accessed, {"date-parts":[["2001",2,3]]}, 'attachment access date is mapped correctly'); @@ -357,4 +357,62 @@ describe("Zotero.Utilities", function() { assert.deepEqual(cslCreators[5], creators[5].expect, 'protected last name prevents parsing'); }); }); + describe("itemFromCSLJSON", function() { + it("should stably perform itemToCSLJSON -> itemFromCSLJSON -> itemToCSLJSON", function() { + let data = loadSampleData('citeProcJSExport'); + + Zotero.DB.beginTransaction(); + + for (let i in data) { + let item = data[i]; + + let zItem = new Zotero.Item(); + Zotero.Utilities.itemFromCSLJSON(zItem, item); + zItem = Zotero.Items.get(zItem.save()); + + let newItem = Zotero.Utilities.itemToCSLJSON(zItem); + + delete newItem.id; + delete item.id; + + assert.deepEqual(newItem, item, i + ' export -> import -> export is stable'); + } + + Zotero.DB.commitTransaction(); + + }); + it("should import exported standalone note", function() { + let note = new Zotero.Item('note'); + note.setNote('Some note longer than 50 characters, which will become the title.'); + note = Zotero.Items.get(note.save()); + + let jsonNote = Zotero.Utilities.itemToCSLJSON(note); + + let zItem = new Zotero.Item(); + Zotero.Utilities.itemFromCSLJSON(zItem, jsonNote); + zItem = Zotero.Items.get(zItem.save()); + + assert.equal(zItem.getField('title'), jsonNote.title, 'title imported correctly'); + }); + it("should import exported standalone attachment", function() { + let file = getTestDataDirectory(); + file.append("empty.pdf"); + + let attachment = Zotero.Items.get(Zotero.Attachments.importFromFile(file)); + attachment.setField('title', 'Empty'); + attachment.setField('accessDate', '2001-02-03 12:13:14'); + attachment.setField('url', 'http://example.com'); + attachment.setNote('Note'); + + attachment.save(); + + let jsonAttachment = Zotero.Utilities.itemToCSLJSON(attachment); + + let zItem = new Zotero.Item(); + Zotero.Utilities.itemFromCSLJSON(zItem, jsonAttachment); + zItem = Zotero.Items.get(zItem.save()); + + assert.equal(zItem.getField('title'), jsonAttachment.title, 'title imported correctly'); + }); + }); });