diff options
author | Alec Kojaev <alec@kojaev.name> | 2021-07-16 15:40:04 +0300 |
---|---|---|
committer | Sean Molenaar <SMillerDev@users.noreply.github.com> | 2021-07-24 14:52:34 +0200 |
commit | 65c15dac38358d5c3a619379b57bd498c070ea6f (patch) | |
tree | 8052e83899b96b7e761f779a43d15feb7921e353 | |
parent | 691c42bdbce50eaa7857f8386c706a4e8c763d60 (diff) |
Reimplement relative time formatting as a filter, dropping dependency on deprecated moment.js
Signed-off-by: Alec Kojaev <alec@kojaev.name>
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | js/.jshintrc | 1 | ||||
-rw-r--r-- | js/controller/ContentController.js | 9 | ||||
-rw-r--r-- | js/filter/RelativeTimestamp.js | 58 | ||||
-rw-r--r-- | js/gulpfile.js | 1 | ||||
-rw-r--r-- | js/karma.conf.js | 1 | ||||
-rw-r--r-- | js/package-lock.json | 5 | ||||
-rw-r--r-- | js/package.json | 1 | ||||
-rw-r--r-- | js/tests/unit/controller/ContentControllerSpec.js | 21 | ||||
-rw-r--r-- | templates/part.content.php | 4 |
10 files changed, 62 insertions, 41 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 112a25771..9c2be3b2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1 ## [16.x.x] ### Changed - Added vue and ng-vue packages +- Reimplemented relative time formatting as a filter + ### Fixed ## [15.x.x] diff --git a/js/.jshintrc b/js/.jshintrc index 92f22ce7c..1f0c276f4 100644 --- a/js/.jshintrc +++ b/js/.jshintrc @@ -25,7 +25,6 @@ "jquery": true, "globals": { "angular": true, - "moment": true, "app": true, "OC": true, "csrfToken": true, diff --git a/js/controller/ContentController.js b/js/controller/ContentController.js index 942618a9c..ed8d0be55 100644 --- a/js/controller/ContentController.js +++ b/js/controller/ContentController.js @@ -198,15 +198,6 @@ app.controller('ContentController', function (Publisher, FeedResource, ItemResou }); }; - this.getRelativeDate = function (timestamp) { - if (timestamp !== undefined && timestamp !== '') { - var languageCode = SettingsResource.get('language'); - return moment.unix(timestamp).locale(languageCode).fromNow() + ''; - } else { - return ''; - } - }; - this.refresh = function () { $route.reload(); }; diff --git a/js/filter/RelativeTimestamp.js b/js/filter/RelativeTimestamp.js new file mode 100644 index 000000000..1a70db4a7 --- /dev/null +++ b/js/filter/RelativeTimestamp.js @@ -0,0 +1,58 @@ +/** + * Nextcloud - News + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Alec Kojaev <alec@kojaev.name> + * @copyright Alec Kojaev 2021 + */ +app.filter('relativeTimestamp', ['SettingsResource', function (SettingsResource) { + 'use strict'; + + const languageCode = SettingsResource.get('language'); + const relFormat = Intl.RelativeTimeFormat ? + new Intl.RelativeTimeFormat(languageCode, { numeric: 'auto' }) : null; + const maxRelDistance = 90*86400*1000; + const relLimits = [ + [ 7*86400*1000, 'week' ], + [ 86400*1000, 'day' ], + [ 3600*1000, 'hour' ], + [ 60*1000, 'minute' ], + [ 1*1000, 'second' ] + ]; + const absLimits = [ + [ 7*86400*1000, { hour: '2-digit', minute: '2-digit', dayPeriod: 'narrow', + year: 'numeric', month: 'short', day: 'numeric' } ], + [ 43200*1000, { hour: '2-digit', minute: '2-digit', dayPeriod: 'narrow', + weekday: 'long' } ], + [ 0, { hour: '2-digit', minute: '2-digit', dayPeriod: 'narrow' } ] + ]; + + return function (timestamp) { + if (!Number.isFinite(timestamp)) { + return timestamp; + } + const ts = new Date(timestamp); + const dist = ts.getTime() - Date.now(); + const absDist = Math.abs(dist); + if (relFormat && absDist < maxRelDistance) { + for (const [ scale, unit ] of relLimits) { + const value = Math.trunc(dist / scale); + if (value !== 0) { + return relFormat.format(value, unit); + } + } + // We arrive here only if distance from now is less than 1 second + return relFormat.format(0, 'second'); + } else { + for (const [ limit, options ] of absLimits) { + if (absDist >= limit) { + return ts.toLocaleString(languageCode, options); + } + } + // We shouldn't be here + return ts.toLocaleString(languageCode, absLimits[absLimits.length - 1][1]); + } + }; +}]); diff --git a/js/gulpfile.js b/js/gulpfile.js index 299918986..7f9d288b5 100644 --- a/js/gulpfile.js +++ b/js/gulpfile.js @@ -30,7 +30,6 @@ const sources = [ 'node_modules/angular-animate/angular-animate.min.js', 'node_modules/angular-route/angular-route.min.js', 'node_modules/angular-sanitize/angular-sanitize.min.js', - 'node_modules/moment/min/moment-with-locales.min.js', 'node_modules/masonry-layout/dist/masonry.pkgd.min.js', 'node_modules/vue/dist/vue.js', 'node_modules/ngVue/build/index.js', diff --git a/js/karma.conf.js b/js/karma.conf.js index 6cf0f4a29..5a6e0af4e 100644 --- a/js/karma.conf.js +++ b/js/karma.conf.js @@ -17,7 +17,6 @@ module.exports = function (config) { // list of files / patterns to load in the browser files: [ 'node_modules/jquery/dist/jquery.js', - 'node_modules/moment/min/moment-with-locales.js', 'node_modules/angular/angular.js', 'node_modules/angular-mocks/angular-mocks.js', 'node_modules/angular-route/angular-route.js', diff --git a/js/package-lock.json b/js/package-lock.json index f866cf39a..3ae44a030 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -5601,11 +5601,6 @@ "minimist": "1.2.5" } }, - "moment": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", - "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" - }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/js/package.json b/js/package.json index 5cb91eb5c..4cff38d31 100644 --- a/js/package.json +++ b/js/package.json @@ -63,7 +63,6 @@ "angular-sanitize": "^1.8.2", "debug": "^4.3.2", "masonry-layout": "^4.2.2", - "moment": "^2.29.1", "ngVue": "^1.7.8", "vue": "^2.6.14" } diff --git a/js/tests/unit/controller/ContentControllerSpec.js b/js/tests/unit/controller/ContentControllerSpec.js index e8992ca8c..b410b7f95 100644 --- a/js/tests/unit/controller/ContentControllerSpec.js +++ b/js/tests/unit/controller/ContentControllerSpec.js @@ -513,27 +513,6 @@ describe('ContentController', function () { expect(ctrl.autoPagingEnabled()).toBe(true); })); - - it('should return relative date', inject(function ($controller, - SettingsResource) { - - SettingsResource.receive({language: 'en'}); - var ctrl = $controller('ContentController', { - data: {}, - }); - - expect(ctrl.getRelativeDate(12)).not.toBe(''); - })); - - - it('should return relative date empty', inject(function ($controller) { - var ctrl = $controller('ContentController', { - data: {} - }); - - expect(ctrl.getRelativeDate('')).toBe(''); - })); - it('should refresh the page', inject(function ($controller) { var route = { current: { diff --git a/templates/part.content.php b/templates/part.content.php index 8c96e7d96..26329ad35 100644 --- a/templates/part.content.php +++ b/templates/part.content.php @@ -50,7 +50,7 @@ date:'yyyy-MM-dd HH:mm:ss' }}" datetime="{{ item.pubDate*1000 | date:'yyyy-MM-ddTHH:mm:ssZ' }}"> - {{ Content.getRelativeDate(item.pubDate) }} + {{ item.pubDate*1000 | relativeTimestamp }} </time> </li> <li ng-click="Content.toggleStar(item.id)" @@ -176,7 +176,7 @@ date:'yyyy-MM-dd HH:mm:ss' }}" datetime="{{ item.pubDate*1000 | date:'yyyy-MM-ddTHH:mm:ssZ' }}"> - {{ Content.getRelativeDate(item.pubDate) }} + {{ item.pubDate*1000 | relativeTimestamp }} </time> <h1 ng-attr-dir="{{item.rtl && 'rtl'}}"> <a class="external" |