diff --git a/chrome/content/zotero/bindings/itembox.xml b/chrome/content/zotero/bindings/itembox.xml index 66f34350c..0fb381911 100644 --- a/chrome/content/zotero/bindings/itembox.xml +++ b/chrome/content/zotero/bindings/itembox.xml @@ -1289,11 +1289,15 @@ case 'dateAdded': case 'dateModified': case 'accessDate': + case 'date': // TEMP - NSF case 'dateSent': case 'dateDue': case 'accepted': + if (fieldName == 'date' && this.item._objectType != 'feedItem') { + break; + } if (valueText) { var date = Zotero.Date.sqlToDate(valueText, true); if (date) { diff --git a/chrome/content/zotero/xpcom/data/feedItem.js b/chrome/content/zotero/xpcom/data/feedItem.js index 79d26dd16..88e7c2719 100644 --- a/chrome/content/zotero/xpcom/data/feedItem.js +++ b/chrome/content/zotero/xpcom/data/feedItem.js @@ -107,27 +107,27 @@ Zotero.FeedItem.prototype.setField = function(field, value) { } Zotero.FeedItem.prototype.fromJSON = function(json) { - // Handle weird formats in feedItems - let dateFields = ['accessDate', 'dateAdded', 'dateModified']; - for (let dateField of dateFields) { - let val = json[dateField]; - if (val) { - let d = new Date(val); - if (isNaN(d.getTime())) { - d = Zotero.Date.sqlToDate(val, true); - } - if (!d || isNaN(d.getTime())) { - d = Zotero.Date.strToDate(val); - d = new Date(d.year, d.month, d.day); - Zotero.debug(dateField + " " + JSON.stringify(d), 1); - } - if (isNaN(d.getTime())) { - Zotero.logError("Discarding invalid " + dateField + " '" + json[dateField] + // Spaghetti to handle weird date formats in feedItems + let val = json.date; + if (val) { + let d = Zotero.Date.sqlToDate(val, true); + if (!d || isNaN(d.getTime())) { + d = Zotero.Date.isoToDate(val); + } + if ((!d || isNaN(d.getTime())) && Zotero.Date.isHTTPDate(val)) { + d = new Date(val); + } + if (!d || isNaN(d.getTime())) { + d = Zotero.Date.strToDate(val); + if (d) { + json.date = [d.year, Zotero.Utilities.lpad(d.month+1, '0', 2), Zotero.Utilities.lpad(d.day, '0', 2)].join('-'); + } else { + Zotero.logError("Discarding invalid date '" + json.date + "' for item " + this.libraryKey); - delete json[dateField]; - continue; + delete json.date; } - json[dateField] = d.toISOString(); + } else { + json.date = Zotero.Date.dateToSQL(d, true); } } Zotero.FeedItem._super.prototype.fromJSON.apply(this, arguments); diff --git a/chrome/content/zotero/xpcom/date.js b/chrome/content/zotero/xpcom/date.js index b66ef69d4..a70c5dabe 100644 --- a/chrome/content/zotero/xpcom/date.js +++ b/chrome/content/zotero/xpcom/date.js @@ -477,6 +477,49 @@ Zotero.Date = new function(){ return date; } + this.isHTTPDate = function(str) { + var dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; + var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec"]; + str = str.trim(); + var temp = str.split(','); + if (temp.length > 1) { + var dayOfWeek = temp[0]; + if(dayNames.indexOf(dayOfWeek) == -1) { + return false; + } + + str = temp[1].trim(); + } + temp = str.split(' '); + temp = temp.filter((t) => ! t.match(/^\s*$/)); + if (temp.length < 5) { + return false; + } + if (!temp[0].trim().match(/[0-3]\d/)) { + return false; + } + if (monthNames.indexOf(temp[1].trim()) == -1) { + return false; + } + if (!temp[2].trim().match(/\d\d\d\d/)) { + return false; + } + temp.splice(0, 3); + var time = temp[0].trim().split(':'); + if (time.length < 2) { + return false; + } + for (let t of time) { + if (!t.match(/\d\d/)) { + return false; + } + } + temp.splice(0, 1); + var zone = temp.join(' ').trim(); + return !!zone.match(/([+-]\d\d\d\d|UTC?|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT)/) + }; + function _insertDateOrderPart(dateOrder, part, partOrder) { if (!dateOrder) { diff --git a/chrome/content/zotero/xpcom/itemTreeView.js b/chrome/content/zotero/xpcom/itemTreeView.js index 7e9fc287c..0f780ba19 100644 --- a/chrome/content/zotero/xpcom/itemTreeView.js +++ b/chrome/content/zotero/xpcom/itemTreeView.js @@ -1031,6 +1031,10 @@ Zotero.ItemTreeView.prototype.getCellText = function (row, column) case 'zotero-items-column-dateAdded': case 'zotero-items-column-dateModified': case 'zotero-items-column-accessDate': + case 'zotero-items-column-date': + if (column.id == 'zotero-items-column-date' && !this.collectionTreeRow.isFeed()) { + break; + } if (val) { var order = Zotero.Date.getLocaleDateOrder(); if (order == 'mdy') { @@ -1039,7 +1043,7 @@ Zotero.ItemTreeView.prototype.getCellText = function (row, column) } else if (order == 'dmy') { order = 'dmy'; - var join = '.'; + var join = '/'; } else if (order == 'ymd') { order = 'YMD'; diff --git a/test/tests/dateTest.js b/test/tests/dateTest.js index 2b4588f67..c1235863d 100644 --- a/test/tests/dateTest.js +++ b/test/tests/dateTest.js @@ -37,4 +37,13 @@ describe("Zotero.Date", function() { assert.isFalse(Zotero.Date.isISODate("2015-04-29 17:28")); }) }) + + describe("#isHTTPDate()", function() { + it("should determine whether a date is an RFC 2822 compliant date", function() { + assert.ok(Zotero.Date.isHTTPDate("Mon, 13 Jun 2016 02:09:08 +4000")); + assert.ok(Zotero.Date.isHTTPDate("13 Jun 2016 02:09:08 +4000")); + assert.ok(Zotero.Date.isHTTPDate("13 Jun 2016 02:09 +4000")); + assert.ok(Zotero.Date.isHTTPDate("13 Jun 2016 02:09 EDT")); + }) + }) }) diff --git a/test/tests/feedItemTest.js b/test/tests/feedItemTest.js index 8e2324e8c..9a46f5bc2 100644 --- a/test/tests/feedItemTest.js +++ b/test/tests/feedItemTest.js @@ -92,18 +92,36 @@ describe("Zotero.FeedItem", function () { }); describe("#fromJSON()", function() { it("should attempt to parse non ISO-8601 dates", function* () { - var json = { - itemType: "journalArticle", - accessDate: "2015-06-07 20:56:00", - dateAdded: "18-20 June 2015", // magically parsed by `new Date()` - dateModified: "07/06/2015", // US - }; - var item = new Zotero.FeedItem; - item.fromJSON(json); - assert.strictEqual(item.getField('accessDate'), '2015-06-07 20:56:00'); - assert.strictEqual(item.getField('dateAdded'), '2015-06-18 20:00:00'); - // sets a timezone specific hour when new Date parses from strings without hour specified. - assert.strictEqual(item.getField('dateModified'), Zotero.Date.dateToSQL(new Date(2015, 6, 6), true)); + Zotero.locale = 'en-US'; + var data = [ + { + itemType: "journalArticle", + date: "2015-06-07 20:56:00" // sql + }, + { + itemType: "journalArticle", + date: "Mon, 13 Jun 2016 06:25:57 EDT" // HTTP + }, + { + itemType: "journalArticle", + date: "18-20 June 2015" // parsed by `strToDate` + }, + { + itemType: "journalArticle", + date: "06/07/2015" // american format also parsed by `strToDate` + } + ]; + var expectedDates = [ + '2015-06-07 20:56:00', + '2016-06-13 10:25:57', + '2015-06-18', + '2015-06-07' + ]; + for (let i = 0; i < data.length; i++) { + var item = new Zotero.FeedItem; + item.fromJSON(data[i]); + assert.strictEqual(item.getField('date'), expectedDates[i]); + } }) }); describe("#save()", function() {