From 290fcb612556d1132f2ea8d0198cddd6e815fec6 Mon Sep 17 00:00:00 2001 From: Viktar Donich Date: Tue, 15 Mar 2016 15:17:06 -0700 Subject: [PATCH] Recognize time format preferences. Bug: Issue 3779 Change-Id: I94d9e8f7a6e688d49be6c22c43b0240ca6768894 --- lib/BUCK | 2 +- lib/LICENSE-moment | 22 ++++ lib/js/BUCK | 8 ++ polygerrit-ui/BUCK | 1 + .../gr-date-formatter/gr-date-formatter.html | 6 +- .../gr-date-formatter/gr-date-formatter.js | 86 +++++++----- .../gr-date-formatter_test.html | 124 +++++++++++++----- 7 files changed, 177 insertions(+), 72 deletions(-) create mode 100644 lib/LICENSE-moment diff --git a/lib/BUCK b/lib/BUCK index f21f207647..9e5c5c3098 100644 --- a/lib/BUCK +++ b/lib/BUCK @@ -15,6 +15,7 @@ define_license(name = 'h2') define_license(name = 'jgit') define_license(name = 'jsch') define_license(name = 'MPL1.1') +define_license(name = 'moment') define_license(name = 'ow2') define_license(name = 'page.js') define_license(name = 'polymer') @@ -258,4 +259,3 @@ maven_jar( sha1 = 'd9a09f7732226af26bf99f19e2cffe0ae219db5b', license = 'DO_NOT_DISTRIBUTE', ) - diff --git a/lib/LICENSE-moment b/lib/LICENSE-moment new file mode 100644 index 0000000000..9ee537448a --- /dev/null +++ b/lib/LICENSE-moment @@ -0,0 +1,22 @@ +Copyright (c) 2011-2016 Tim Wood, Iskren Chernev, Moment.js contributors + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/js/BUCK b/lib/js/BUCK index 948f9b47bf..b0bdb67ce3 100644 --- a/lib/js/BUCK +++ b/lib/js/BUCK @@ -256,6 +256,14 @@ bower_component( sha1 = '5a68250d6d9abcd576f116dc4fc7312426323883', ) +bower_component( + name = 'moment', + package = 'moment/moment', + version = '2.12.0', + license = 'moment', + sha1 = '508d53de8f49ab87f03e209e5073e339107ed3e6', +) + bower_component( name = 'neon-animation', package = 'polymerelements/neon-animation', diff --git a/polygerrit-ui/BUCK b/polygerrit-ui/BUCK index 0a562f9329..4d8144ffb7 100644 --- a/polygerrit-ui/BUCK +++ b/polygerrit-ui/BUCK @@ -10,6 +10,7 @@ bower_components( '//lib/js:iron-input', '//lib/js:iron-overlay-behavior', '//lib/js:iron-selector', + '//lib/js:moment', '//lib/js:page', '//lib/js:polymer', '//lib/js:promise-polyfill', diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html index 6d4b2ea71d..01deeda1f7 100644 --- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html +++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html @@ -15,6 +15,9 @@ limitations under the License. --> + + + diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js index cb77cc13ad..35347f5ddf 100644 --- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js +++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js @@ -19,10 +19,12 @@ DAY: 1000 * 60 * 60 * 24, }; - var ShortMonthNames = [ - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', - 'Nov', 'Dec' - ]; + var TimeFormats = { + TIME_12: 'h:mm A', // 2:14 PM + TIME_24: 'H:mm', // 14:14 + MONTH_DAY: 'MMM DD', // Aug 29 + MONTH_DAY_YEAR: 'MMM DD, YYYY', // Aug 29, 1997 + }; Polymer({ is: 'gr-date-formatter', @@ -31,46 +33,58 @@ dateStr: { type: String, value: null, - notify: true - } + notify: true, + }, + timeFormat: { + type: String, + value: 'HHMM_24', + notify: true, + }, }, - _computeDateStr: function(dateStr) { - return this._dateStr(this._parseDateStr(dateStr), new Date()); + attached: function() { + this._fetchPreferences(); }, - _parseDateStr: function(dateStr) { - if (!dateStr) { return null; } - return util.parseDate(dateStr); + _fetchPreferences: function() { + this.$.restAPI.getPreferences().then(function(preferences) { + this.timeFormat = preferences && preferences.time_format; + }.bind(this)); }, - _dateStr: function(t, now) { - if (!t) { return ''; } - var diff = now.getTime() - t.getTime(); - if (diff < Duration.DAY && t.getDay() == now.getDay()) { - // Within 24 hours and on the same day: - // '2:14 AM' - var pm = t.getHours() >= 12; - var hours = t.getHours(); - if (hours == 0) { - hours = 12; - } else if (hours > 12) { - hours = t.getHours() - 12; + /** + * Return true if date is within 24 hours and on the same day. + */ + _isWithinDay: function(now, date) { + var diff = -date.diff(now); + return diff < Duration.DAY && date.day() == now.getDay(); + }, + + /** + * Returns true if date is from one to six months. + */ + _isWithinHalfYear: function(now, date) { + var diff = -date.diff(now); + return (date.day() != now.getDay() || diff >= Duration.DAY) && + diff < 180 * Duration.DAY; + }, + + _computeDateStr: function(dateStr, timeFormat) { + if (!dateStr) { return ''; } + var date = moment(dateStr + 'Z'); + if (!date.isValid()) { return ''; } + var now = new Date(); + var format = TimeFormats.MONTH_DAY_YEAR; + if (this._isWithinDay(now, date)) { + if (this.timeFormat == 'HHMM_12') { + format = TimeFormats.TIME_12; + } else { + format = TimeFormats.TIME_24; } - var minutes = t.getMinutes() < 10 ? '0' + t.getMinutes() : - t.getMinutes(); - return hours + ':' + minutes + (pm ? ' PM' : ' AM'); - } else if ((t.getDay() != now.getDay() || diff >= Duration.DAY) && - diff < 180 * Duration.DAY) { - // From one to six months: - // 'Aug 29' - return ShortMonthNames[t.getMonth()] + ' ' + t.getDate(); - } else if (diff >= 180 * Duration.DAY) { - // More than six months: - // 'Aug 29, 1997' - return ShortMonthNames[t.getMonth()] + ' ' + t.getDate() + ', ' + - t.getFullYear(); + } else if (this._isWithinHalfYear(now, date)) { + format = TimeFormats.MONTH_DAY; } + return date.format(format); }, }); })(); diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html index 9bba517ece..932cba4962 100644 --- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html +++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html @@ -34,51 +34,107 @@ limitations under the License. suite('gr-date-formatter tests', function() { var element; - setup(function() { - element = fixture('basic'); - }); - - test('date is parsed correctly', function() { - assert.notOk((new Date('foo')).valueOf()); - var d = element._parseDateStr(element.getAttribute('date-str')); - assert.isAbove(d.valueOf(), 0); - }); - + /** + * Parse server-formatter date and normalize into current timezone. + */ function normalizedDate(dateStr) { - var d = new Date(dateStr); + var d = new Date(util.parseDate(dateStr)); d.setMinutes(d.getMinutes() + d.getTimezoneOffset()); return d; } function testDates(nowStr, dateStr, expected) { - var now = normalizedDate(nowStr); - var t = normalizedDate(dateStr); - assert.equal(element._dateStr(t, now), expected); + // Normalize and convert the date to mimic server response. + dateStr = normalizedDate(dateStr) + .toJSON().replace('T', ' ').slice(0, -1); + var clock = sinon.useFakeTimers( + new Date(normalizedDate(nowStr)).getTime()); + element.dateStr = dateStr; + assert.equal(element.$$('span').textContent, expected); + clock.restore(); } - test('dates strings are correct', function() { - // Within 24 hours on same day. - testDates('2015-07-29T20:34:00.000Z', - '2015-07-29T15:34:00.000Z', - '3:34 PM'); - testDates('2016-01-27T17:41:00.000Z', - '2016-01-27T12:41:00.000Z', - '12:41 PM'); + function stubPreferences(preferences) { + var preferencesPromise = Promise.resolve(preferences); + stub('gr-rest-api-interface', { + getPreferences: sinon.stub().returns(preferencesPromise), + }); + return preferencesPromise; + } - // Within 24 hours on different days. - testDates('2015-07-29T03:34:00.000Z', - '2015-07-28T20:25:00.000Z', - 'Jul 28'); + suite('not signed in', function() { + setup(function() { + return stubPreferences(null).then(function() { + element = fixture('basic'); + }); + }); - // More than 24 hours. Less than six months. - testDates('2015-07-29T20:34:00.000Z', - '2015-06-15T03:25:00.000Z', - 'Jun 15'); + test('invalid dates are quietly rejected', function() { + assert.notOk((new Date('foo')).valueOf()); + element.dateStr = 'foo'; + assert.equal(element.$$('span').textContent, ''); + }); - // More than six months. - testDates('2015-09-15T20:34:00.000Z', - '2015-01-15T03:25:00.000Z', - 'Jan 15, 2015'); + test('Within 24 hours on same day', function() { + testDates('2015-07-29 20:34:14.985000000', + '2015-07-29 15:34:14.985000000', + '15:34'); + testDates('2016-01-27 17:41:14.985000000', + '2016-01-27 12:41:14.985000000', + '12:41'); + }); + + test('Within 24 hours on different days', function() { + testDates('2015-07-29 03:34:14.985000000', + '2015-07-28 20:25:14.985000000', + 'Jul 28'); + }); + + test('More than 24 hours but less than six months', function() { + testDates('2015-07-29 20:34:14.985000000', + '2015-06-15 03:25:14.985000000', + 'Jun 15'); + }); + + test('More than six months', function() { + testDates('2015-09-15 20:34:00.000000000', + '2015-01-15 03:25:00.000000000', + 'Jan 15, 2015'); + }); + }); + + suite('signed in with 12 hours time format preference', function() { + setup(function() { + return stubPreferences({time_format: 'HHMM_12'}).then(function() { + element = fixture('basic'); + }); + }); + + test('Within 24 hours on same day', function() { + testDates('2015-07-29 20:34:14.985000000', + '2015-07-29 15:34:14.985000000', + '3:34 PM'); + testDates('2016-01-27 17:41:14.985000000', + '2016-01-27 12:41:14.985000000', + '12:41 PM'); + }); + }); + + suite('signed in with 24 hours time format preference', function() { + setup(function() { + return stubPreferences({time_format: 'HHMM_24'}).then(function() { + element = fixture('basic'); + }); + }); + + test('Within 24 hours on same day', function() { + testDates('2015-07-29 20:34:14.985000000', + '2015-07-29 15:34:14.985000000', + '15:34'); + testDates('2016-01-27 17:41:14.985000000', + '2016-01-27 12:41:14.985000000', + '12:41'); + }); }); });