All files / app/assets/javascripts/lib/utils/datetime timeago_utility.js

64.29% Statements 45/70
100% Branches 23/23
37.5% Functions 15/40
64.29% Lines 45/70

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136                  720x         720x 720x   720x                         3x 1x     720x 17x 13x   4x 4x       720x 720x   720x                       1x         720x 2x 1x   1x 1x       720x 720x   720x     6x 1x         1x   6x       6x     720x 2693x             720x 5x 5x 4x     5x 2x       3x   2x       3x               720x 66x 6x   60x 43x   17x    
import * as timeago from 'timeago.js';
import { languageCode, s__, createDateTimeFormat } from '../../../locale';
import { formatDate } from './date_format_utility';
 
/**
 * Timeago uses underscores instead of dashes to separate language from country code.
 *
 * see https://github.com/hustcc/timeago.js/tree/v3.0.0/locales
 */
const timeagoLanguageCode = languageCode().replace(/-/g, '_');
 
/**
 * Registers timeago locales
 */
const memoizedLocaleRemaining = () => {
  const cache = [];
 
  const timeAgoLocaleRemaining = [
    () => [s__('Timeago|just now'), s__('Timeago|right now')],
    () => [s__('Timeago|just now'), s__('Timeago|%s seconds remaining')],
    () => [s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
    () => [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')],
    () => [s__('Timeago|1 hour ago'), s__('Timeago|1 hour remaining')],
    () => [s__('Timeago|%s hours ago'), s__('Timeago|%s hours remaining')],
    () => [s__('Timeago|1 day ago'), s__('Timeago|1 day remaining')],
    () => [s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')],
    () => [s__('Timeago|1 week ago'), s__('Timeago|1 week remaining')],
    () => [s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')],
    () => [s__('Timeago|1 month ago'), s__('Timeago|1 month remaining')],
    () => [s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')],
    () => [s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
    () => [s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
  ];
 
  return (number, index) => {
    if (cache[index]) {
      return cache[index];
    }
    cache[index] = timeAgoLocaleRemaining[index] && timeAgoLocaleRemaining[index]();
    return cache[index];
  };
};
 
const memoizedLocale = () => {
  const cache = [];
 
  const timeAgoLocale = [
    () => [s__('Timeago|just now'), s__('Timeago|right now')],
    () => [s__('Timeago|just now'), s__('Timeago|in %s seconds')],
    () => [s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
    () => [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')],
    () => [s__('Timeago|1 hour ago'), s__('Timeago|in 1 hour')],
    () => [s__('Timeago|%s hours ago'), s__('Timeago|in %s hours')],
    () => [s__('Timeago|1 day ago'), s__('Timeago|in 1 day')],
    () => [s__('Timeago|%s days ago'), s__('Timeago|in %s days')],
    () => [s__('Timeago|1 week ago'), s__('Timeago|in 1 week')],
    () => [s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')],
    () => [s__('Timeago|1 month ago'), s__('Timeago|in 1 month')],
    () => [s__('Timeago|%s months ago'), s__('Timeago|in %s months')],
    () => [s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
    () => [s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
  ];
 
  return (number, index) => {
    if (cache[index]) {
      return cache[index];
    }
    cache[index] = timeAgoLocale[index] && timeAgoLocale[index]();
    return cache[index];
  };
};
 
timeago.register(timeagoLanguageCode, memoizedLocale());
timeago.register(`${timeagoLanguageCode}-remaining`, memoizedLocaleRemaining());
 
let memoizedFormatter = null;
 
function setupAbsoluteFormatter() {
  if (memoizedFormatter === null) {
    const formatter = createDateTimeFormat({
      dateStyle: 'medium',
      timeStyle: 'short',
    });
 
    memoizedFormatter = {
      format(date) {
        return formatter.format(date instanceof Date ? date : new Date(date));
      },
    };
  }
  return memoizedFormatter;
}
 
export const getTimeago = () =>
  window.gon?.time_display_relative === false ? setupAbsoluteFormatter() : timeago;
 
/**
 * For the given elements, sets a tooltip with a formatted date.
 * @param {Array<Node>|NodeList} elements
 * @param {Boolean} updateTooltip
 */
export const localTimeAgo = (elements, updateTooltip = true) => {
  const { format } = getTimeago();
  elements.forEach((el) => {
    el.innerText = format(el.dateTime, timeagoLanguageCode);
  });
 
  if (!updateTooltip) {
    return;
  }
 
  function addTimeAgoTooltip() {
    elements.forEach((el) => {
      // Recreate with custom template
      el.setAttribute('title', formatDate(el.dateTime));
    });
  }
 
  requestIdleCallback(addTimeAgoTooltip);
};
 
/**
 * Returns remaining or passed time over the given time.
 * @param {*} time
 * @param {*} expiredLabel
 */
export const timeFor = (time, expiredLabel) => {
  if (!time) {
    return '';
  }
  if (new Date(time) < new Date()) {
    return expiredLabel || s__('Timeago|Past due');
  }
  return timeago.format(time, `${timeagoLanguageCode}-remaining`).trim();
};