PERF: generates dates tooltip on demand (#13944)

PERF: generates dates tooltip on demand (#13944)

diff --git a/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js.es6 b/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js.es6
index 53d8d04..108fae4 100644
--- a/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js.es6
+++ b/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js.es6
@@ -1,10 +1,72 @@
+import deprecated from "discourse-common/lib/deprecated";
+import { getOwner } from "discourse-common/lib/get-owner";
+import { hidePopover, showPopover } from "discourse/lib/d-popover";
 import LocalDateBuilder from "../lib/local-date-builder";
-import showModal from "discourse/lib/show-modal";
 import { withPluginApi } from "discourse/lib/plugin-api";
+import showModal from "discourse/lib/show-modal";
+
+export function applyLocalDates(dates, siteSettings) {
+  if (!siteSettings.discourse_local_dates_enabled) {
+    return;
+  }
+
+  const currentUserTZ = moment.tz.guess();
+
+  dates.forEach((element) => {
+    const opts = buildOptionsFromElement(element, siteSettings);
+
+    const localDateBuilder = new LocalDateBuilder(opts, currentUserTZ).build();
+    element.innerText = "";
+    element.insertAdjacentHTML(
+      "beforeend",
+      `
+        <svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
+          <use xlink:href="#globe-americas"></use>
+        </svg>
+        <span class="relative-time">${localDateBuilder.formated}</span>
+      `
+    );
+    element.setAttribute("aria-label", localDateBuilder.textPreview);
+
+    const classes = ["cooked-date"];
+    if (localDateBuilder.pastEvent) {
+      classes.push("past");
+    }
+    element.classList.add(...classes);
+  });
+}
+
+function buildOptionsFromElement(element, siteSettings) {
+  const opts = {};
+  const dataset = element.dataset;
+  opts.time = dataset.time;
+  opts.date = dataset.date;
+  opts.recurring = dataset.recurring;
+  opts.timezones = (
+    dataset.timezones ||
+    siteSettings.discourse_local_dates_default_timezones ||
+    "Etc/UTC"
+  )
+    .split("|")
+    .filter(Boolean);
+  opts.timezone = dataset.timezone;
+  opts.calendar = (dataset.calendar || "on") === "on";
+  opts.displayedTimezone = dataset.displayedTimezone;
+  opts.format = dataset.format || (opts.time ? "LLL" : "LL");
+  opts.countdown = dataset.countdown;
+  return opts;
+}
 
 function initializeDiscourseLocalDates(api) {
-  api.decorateCooked(
-    ($elem) => $(".discourse-local-date", $elem).applyLocalDates(),
+  const siteSettings = api.container.lookup("site-settings:main");
+
+  api.decorateCookedElement(
+    (elem) => {
+      applyLocalDates(
+        elem.querySelectorAll(".discourse-local-date"),
+        siteSettings
+      );
+    },
     { id: "discourse-local-date" }
   );
 
@@ -30,87 +92,84 @@ function initializeDiscourseLocalDates(api) {
   });
 }
 
+function buildHtmlPreview(element, siteSettings) {
+  const opts = buildOptionsFromElement(element, siteSettings);
+  const localDateBuilder = new LocalDateBuilder(
+    opts,
+    moment.tz.guess()
+  ).build();
+
+  const htmlPreviews = localDateBuilder.previews.map((preview) => {
+    const previewNode = document.createElement("div");
+    previewNode.classList.add("preview");
+    if (preview.current) {
+      previewNode.classList.add("current");
+    }
+
+    const timezoneNode = document.createElement("span");
+    timezoneNode.classList.add("timezone");
+    timezoneNode.innerText = preview.timezone;
+    previewNode.appendChild(timezoneNode);
+
+    const dateTimeNode = document.createElement("span");
+    dateTimeNode.classList.add("date-time");
+    dateTimeNode.innerText = preview.formated;
+    previewNode.appendChild(dateTimeNode);
+
+    return previewNode;
+  });
+
+  const previewsNode = document.createElement("div");
+  previewsNode.classList.add("locale-dates-previews");
+  htmlPreviews.forEach((htmlPreview) => previewsNode.appendChild(htmlPreview));
+
+  return previewsNode.outerHTML;
+}
+
 export default {
   name: "discourse-local-dates",
 
+  showDatePopover(event) {
+    const siteSettings = getOwner(this).lookup("site-settings:main");
+
+    if (event?.target?.classList?.contains("discourse-local-date")) {
+      showPopover(event, {
+        htmlContent: buildHtmlPreview(event.target, siteSettings),
+      });
+    }
+  },
+
+  hideDatePopover(event) {
+    if (event?.target?.classList?.contains("discourse-local-date")) {
+      hidePopover(event);
+    }
+  },
+
   initialize(container) {
+    const router = container.lookup("router:main");
+    router.on("routeWillChange", hidePopover);
+
+    window.addEventListener("click", this.showDatePopover);
+    window.addEventListener("mouseover", this.showDatePopover);
+    window.addEventListener("mouseout", this.hideDatePopover);
+
     const siteSettings = container.lookup("site-settings:main");
     if (siteSettings.discourse_local_dates_enabled) {
-      const currentUserTZ = moment.tz.guess();
-
       $.fn.applyLocalDates = function () {
-        return this.each(function () {
-          const opts = {};
-          const dataset = this.dataset;
-          opts.time = dataset.time;
-          opts.date = dataset.date;
-          opts.recurring = dataset.recurring;
-          opts.timezones = (
-            dataset.timezones ||
-            siteSettings.discourse_local_dates_default_timezones ||
-            "Etc/UTC"
-          )
-            .split("|")
-            .filter(Boolean);
-          opts.timezone = dataset.timezone;
-          opts.calendar = (dataset.calendar || "on") === "on";
-          opts.displayedTimezone = dataset.displayedTimezone;
-          opts.format = dataset.format || (opts.time ? "LLL" : "LL");
-          opts.countdown = dataset.countdown;
-
-          const localDateBuilder = new LocalDateBuilder(
-            opts,
-            currentUserTZ
-          ).build();
-
-          const htmlPreviews = localDateBuilder.previews.map((preview) => {
-            const previewNode = document.createElement("div");
-            previewNode.classList.add("preview");
-            if (preview.current) {
-              previewNode.classList.add("current");
-            }
-
-            const timezoneNode = document.createElement("span");
-            timezoneNode.classList.add("timezone");
-            timezoneNode.innerText = preview.timezone;
-            previewNode.appendChild(timezoneNode);
-
-            const dateTimeNode = document.createElement("span");
-            dateTimeNode.classList.add("date-time");
-            dateTimeNode.innerText = preview.formated;
-            previewNode.appendChild(dateTimeNode);
-
-            return previewNode;
-          });
-
-          const previewsNode = document.createElement("div");
-          previewsNode.classList.add("locale-dates-previews");
-          htmlPreviews.forEach((htmlPreview) =>
-            previewsNode.appendChild(htmlPreview)
-          );
-
-          this.innerText = "";
-          this.insertAdjacentHTML(
-            "beforeend",
-            `
-              <svg class="fa d-icon d-icon-globe-americas svg-icon" xmlns="http://www.w3.org/2000/svg">
-                <use xlink:href="#globe-americas"></use>
-              </svg>
-              <span class="relative-time">${localDateBuilder.formated}</span>
-            `
-          );
-          this.setAttribute("aria-label", localDateBuilder.textPreview);
-          this.dataset.htmlTooltip = previewsNode.outerHTML;
-
-          const classes = ["cooked-date"];
-          if (localDateBuilder.pastEvent) {
-            classes.push("past");
-          }
-          this.classList.add(...classes);
-        });
+        deprecated(
+          "`$.applyLocalDates()` is deprecated, import and use `applyLocalDates()` instead."
+        );
+
+        return applyLocalDates(this.toArray(), siteSettings);
       };
 

[... diff too long, it was truncated ...]

GitHub sha: 11668ee85b4cd181efa7baa2386047091acf3c17

This commit appears in #13944 which was approved by ZogStriP. It was merged by jjaffeux.