aboutsummaryrefslogtreecommitdiff
path: root/static/js/timeago.ts
blob: 7c1973d5db8c39ee7245ce8c6212136950a1de5e (plain)
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
(function () {
  type second = number;
  type millisecond = number;

  const relative = new Intl.RelativeTimeFormat("en", {
    localeMatcher: "best fit",
    numeric: "always",
    style: "long",
  });

  function viewport(element) {
    const options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : { offset: 250 };
    const view = element.getBoundingClientRect();
    return view.top    >= -options.offset
        && view.left   >= -options.offset
        && view.bottom <= (self.innerHeight || document.documentElement.clientHeight) + options.offset
        && view.right  <= (self.innerWidth  || document.documentElement.clientWidth)  + options.offset;
  }

  const date = function (update) {
    const elements = document.querySelectorAll("time");
    for (let i = 0; i < elements.length; ++i) {
      const offscreen = !viewport(elements[i]);
      const hidden = elements[i].offsetParent === null;
      if ((update === "viewport") && (offscreen || hidden)) continue;

      (function (element) {
        try {
          if (element.dataset.type === "disabled") return;

          const time: millisecond = new Date(element.dateTime) || new Date();
          const interval: second = ((new Date().getTime() - time.getTime()) / 1000);

          const seconds: number = Math.round(interval);
          const minutes: number = Math.round(seconds / 60);
          const hours:   number = Math.round(minutes / 60);
          const days:    number = Math.round(hours   / 24);

          const past = Math.sign(seconds) === 1;
          const future = Math.sign(seconds) === -1;

          let tiny = function (string, place) {
            return string.split(" ").slice(0, place).join(" ") + string.split(" ")[place].charAt(0);
          }

          if (element.dataset.type === "default") { tiny = function (string) { return string; }; }

          if (element.dataset.type === "localDate") {
            return element.textContent = new Intl.DateTimeFormat([], { dateStyle: "medium", }).format(time).replace(",", "");
          }

          if (element.dataset.type === "localTime") {
            return element.textContent = new Intl.DateTimeFormat([], {
              hour12: false,
              timeStyle: "short",
            }).format(time) + " " + new Intl.DateTimeFormat([], { timeZoneName: "short" }).format(time).split(" ")[1];
          }

          if (past) {
            if (seconds <= 60)  { return element.textContent = tiny(relative.format(-1 * seconds, "second",), 1); }
            if (minutes <= 120) { return element.textContent = tiny(relative.format(-1 * minutes, "minute",), 1); }
            if (hours   <= 48)  { return element.textContent = tiny(relative.format(-1 * hours,   "hour",), 1);   }
            if (days    <= 7)   { return element.textContent = tiny(relative.format(-1 * days,    "day",), 1);    }
          }

          if (future) {
            if (-1 * days    >= 4)  { return element.textContent = tiny(relative.format(-1 * days,    "day",), 2);    }
            if (-1 * hours   >= 3)  { return element.textContent = tiny(relative.format(-1 * hours,   "hour",), 2);   }
            if (-1 * minutes >= 2)  { return element.textContent = tiny(relative.format(-1 * minutes, "minute",), 2); }
            if (-1 * seconds >= 1)  { return element.textContent = tiny(relative.format(-1 * seconds, "second",), 2); }
          }
        } catch (error) {
          console.error("ERROR: Relative time resolution failed", error);
        }
      })(elements[i]);
    }
  };

  const substitution = setInterval(date, 4);

  ["scroll", "URLChangedCustomEvent"].forEach(function (event) {
    self.addEventListener(event, function () {
      date("viewport");
    });
  });

  self.addEventListener("DOMContentLoaded", function () {
    setTimeout(function () {
      clearInterval(substitution);
      setInterval(function () { date("viewport"); }, 1000);
    }, 1000);
  });
})();