aboutsummaryrefslogtreecommitdiff
path: root/static/js/timeago.ts
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/timeago.ts')
-rw-r--r--static/js/timeago.ts93
1 files changed, 93 insertions, 0 deletions
diff --git a/static/js/timeago.ts b/static/js/timeago.ts
new file mode 100644
index 0000000..7c1973d
--- /dev/null
+++ b/static/js/timeago.ts
@@ -0,0 +1,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);
+ });
+})();