diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index 08a2646fcf..00b3697d37 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -357,6 +357,9 @@ field.formatter.settings.timestamp: granularity: type: integer label: 'Granularity' + refresh: + type: integer + label: 'Refresh interval in seconds' field.formatter.settings.timestamp_ago: type: mapping diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php index d3712f31f4..c94cdaed78 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php @@ -105,6 +105,7 @@ public static function defaultSettings() { 'future_format' => '@interval hence', 'past_format' => '@interval ago', 'granularity' => 2, + 'refresh' => 60, ], ] + parent::defaultSettings(); } @@ -198,6 +199,15 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#states' => $states, ]; + $form['timeago']['refresh'] = [ + '#type' => 'select', + '#title' => $this->t('Refresh interval (seconds)'), + '#description' => $this->t("The interval to refresh the displayed 'time ago'."), + '#default_value' => $timeago['refresh'], + '#options' => $this->getRefreshIntervals(), + '#states' => $states, + ]; + return $form; } @@ -237,6 +247,11 @@ public function settingsSummary() { $interval = $this->dateFormatter->formatTimeDiffSince($timestamp, $options); $display = new FormattableMarkup($timeago['past_format'], ['@interval' => $interval]); $summary[] = $this->t('Past date: %display', ['%display' => $display]); + + if ($timeago['refresh']) { + $refresh_intervals = $this->getRefreshIntervals(); + $summary[] = $this->t('Refresh in @interval', ['@interval' => $refresh_intervals[$timeago['refresh']]]); + } } return $summary; @@ -319,4 +334,22 @@ protected function buildStates(array $path, array $conditions) { ]; } + /** + * Returns the refresh interval options for the jQuery 'time ago' display. + * + * @return array + * A list of refresh time intervals. + */ + protected function getRefreshIntervals() { + return [ + 0 => $this->t('No refresh'), + 1 => $this->t('1 second'), + 10 => $this->t('10 seconds'), + 15 => $this->t('15 seconds'), + 30 => $this->t('30 seconds'), + 60 => $this->t('1 minute'), + 300 => $this->t('5 minutes'), + ]; + } + } diff --git a/core/misc/timeago.es6.js b/core/misc/timeago.es6.js index 4cd3bdf36a..4e50746c31 100644 --- a/core/misc/timeago.es6.js +++ b/core/misc/timeago.es6.js @@ -14,25 +14,33 @@ */ Drupal.behaviors.timestampAsTimeAgo = { attach: function (context, settings) { - // @todo Refresh on an interval configurable via formatter settings. $('time.js-timeago') .once('timeago') .each(function () { var timestamp = (new Date($(this).attr('datetime'))).getTime(); var timeagoSettings = JSON.parse(atob($(this).attr('data-drupal-timeago'))); - var interval, format; var options = { granularity: timeagoSettings.granularity }; - var now = Date.now(); + var element = this; - if (timestamp > now) { - interval = Drupal.dateFormatter.formatDiff(now, timestamp, options); - format = timeagoSettings.future_format; - } - else { - interval = Drupal.dateFormatter.formatDiff(timestamp, now, options); - format = timeagoSettings.past_format; + var showTimeAgo = function () { + var interval, format; + now = Date.now(); + + if (timestamp > now) { + interval = Drupal.dateFormatter.formatDiff(now, timestamp, options); + format = timeagoSettings.future_format; + } + else { + interval = Drupal.dateFormatter.formatDiff(timestamp, now, options); + format = timeagoSettings.past_format; + } + $(element).text(Drupal.t(format, {'@interval': interval})); + }; + + showTimeAgo(); + if (timeagoSettings.refresh > 0) { + setInterval(showTimeAgo, timeagoSettings.refresh * 1000); } - $(this).text(Drupal.t(format, {'@interval': interval})); }) } }; @@ -93,7 +101,7 @@ output.push(Drupal.formatPlural(units, '1 year', '@count years')); break; case 'month': - output.push(Drupal.formatPlural(units, '1 months', '@count months')); + output.push(Drupal.formatPlural(units, '1 month', '@count months')); break; case 'week': output.push(Drupal.formatPlural(units, '1 week', '@count weeks')); diff --git a/core/misc/timeago.js b/core/misc/timeago.js index 5a5015d7f4..8e99a41360 100644 --- a/core/misc/timeago.js +++ b/core/misc/timeago.js @@ -14,18 +14,27 @@ $('time.js-timeago').once('timeago').each(function () { var timestamp = new Date($(this).attr('datetime')).getTime(); var timeagoSettings = JSON.parse(atob($(this).attr('data-drupal-timeago'))); - var interval, format; var options = { granularity: timeagoSettings.granularity }; - var now = Date.now(); + var element = this; - if (timestamp > now) { - interval = Drupal.dateFormatter.formatDiff(now, timestamp, options); - format = timeagoSettings.future_format; - } else { - interval = Drupal.dateFormatter.formatDiff(timestamp, now, options); - format = timeagoSettings.past_format; + var showTimeAgo = function showTimeAgo() { + var interval, format; + now = Date.now(); + + if (timestamp > now) { + interval = Drupal.dateFormatter.formatDiff(now, timestamp, options); + format = timeagoSettings.future_format; + } else { + interval = Drupal.dateFormatter.formatDiff(timestamp, now, options); + format = timeagoSettings.past_format; + } + $(element).text(Drupal.t(format, { '@interval': interval })); + }; + + showTimeAgo(); + if (timeagoSettings.refresh > 0) { + setInterval(showTimeAgo, timeagoSettings.refresh * 1000); } - $(this).text(Drupal.t(format, { '@interval': interval })); }); } }; @@ -64,7 +73,7 @@ output.push(Drupal.formatPlural(units, '1 year', '@count years')); break; case 'month': - output.push(Drupal.formatPlural(units, '1 months', '@count months')); + output.push(Drupal.formatPlural(units, '1 month', '@count months')); break; case 'week': output.push(Drupal.formatPlural(units, '1 week', '@count weeks'));