From 65c15dac38358d5c3a619379b57bd498c070ea6f Mon Sep 17 00:00:00 2001 From: Alec Kojaev Date: Fri, 16 Jul 2021 15:40:04 +0300 Subject: Reimplement relative time formatting as a filter, dropping dependency on deprecated moment.js Signed-off-by: Alec Kojaev --- js/.jshintrc | 1 - js/controller/ContentController.js | 9 ---- js/filter/RelativeTimestamp.js | 58 +++++++++++++++++++++++ js/gulpfile.js | 1 - js/karma.conf.js | 1 - js/package-lock.json | 5 -- js/package.json | 1 - js/tests/unit/controller/ContentControllerSpec.js | 21 -------- 8 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 js/filter/RelativeTimestamp.js (limited to 'js') 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 + * @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: { -- cgit v1.2.3