DEV: local-dates refactoring (#6692)

DEV: local-dates refactoring (#6692)

From eb1607bd98fc7df3f75508c8b892bc21e43f920c Mon Sep 17 00:00:00 2001
From: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Date: Wed, 28 Nov 2018 16:19:25 +0100
Subject: [PATCH] DEV: local-dates refactoring (#6692)


diff --git a/plugins/discourse-local-dates/assets/javascripts/discourse-local-dates.js.no-module.es6 b/plugins/discourse-local-dates/assets/javascripts/discourse-local-dates.js.no-module.es6
index 15fcee7..65bfa99 100644
--- a/plugins/discourse-local-dates/assets/javascripts/discourse-local-dates.js.no-module.es6
+++ b/plugins/discourse-local-dates/assets/javascripts/discourse-local-dates.js.no-module.es6
@@ -1,294 +1,284 @@
 (function($) {
-  $.fn.applyLocalDates = function(repeat) {
-    const processElement = ($element, options = {}) => {
-      if (this.timeout) clearTimeout(this.timeout);
-
-      repeat = repeat || true;
-      const utc = moment().utc();
-      const dateTime = options.time
-        ? `${options.date} ${options.time}`
-        : options.date;
-      let utcDateTime;
-
-      let displayedTimezone;
-      if (options.time) {
-        displayedTimezone = options.displayedTimezone || moment.tz.guess();
-      } else {
-        displayedTimezone =
-          options.displayedTimezone || options.timezone || moment.tz.guess();
-      }
-
-      // if timezone given we convert date and time from given zone to Etc/UTC
-      if (options.timezone) {
-        utcDateTime = _applyZoneToDateTime(dateTime, options.timezone);
+  const DATE_TEMPLATE = `
+    <span>
+      <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"></span>
+    </span>
+  `;
+
+  const PREVIEW_TEMPLATE = `
+    <div class='preview'>
+      <span class='timezone'></span>
+      <span class='date-time'></span>
+    </div>
+  `;
+
+  function processElement($element, options = {}) {
+    clearTimeout(this.timeout);
+
+    const utc = moment().utc();
+    const dateTime = options.time
+      ? `${options.date} ${options.time}`
+      : options.date;
+    let utcDateTime;
+
+    let displayedTimezone;
+    if (options.time) {
+      displayedTimezone = options.displayedTimezone || moment.tz.guess();
+    } else {
+      displayedTimezone =
+        options.displayedTimezone || options.timezone || moment.tz.guess();
+    }
+
+    // if timezone given we convert date and time from given zone to Etc/UTC
+    if (options.timezone) {
+      utcDateTime = _applyZoneToDateTime(dateTime, options.timezone);
+    } else {
+      utcDateTime = moment.utc(dateTime);
+    }
+
+    if (utcDateTime < utc) {
+      // if event is in the past we want to bump it no next occurrence when
+      // recurring is set
+      if (options.recurring) {
+        utcDateTime = _applyRecurrence(utcDateTime, options.recurring);
       } else {
-        utcDateTime = moment.utc(dateTime);
+        $element.addClass("past");
       }
+    }
+
+    // once we have the correct UTC date we want
+    // we adjust it to watching user timezone
+    const adjustedDateTime = utcDateTime.tz(displayedTimezone);
+
+    const previews = _generatePreviews(
+      adjustedDateTime.clone(),
+      displayedTimezone,
+      options
+    );
+    const textPreview = _generateTextPreview(previews);
+    const htmlPreview = _generateHtmlPreview(previews);
+
+    const formatedDateTime = _applyFormatting(
+      adjustedDateTime,
+      displayedTimezone,
+      options
+    );
+
+    $element
+      .html(DATE_TEMPLATE)
+      .attr("title", textPreview)
+      .attr("data-html-tooltip", `<div class="previews">${htmlPreview}</div>`)
+      .addClass("cooked-date")
+      .find(".relative-time")
+      .text(formatedDateTime);
+
+    this.timeout = setTimeout(() => processElement($element, options), 10000);
+  }
+
+  function _formatTimezone(timezone) {
+    return timezone
+      .replace("_", " ")
+      .replace("Etc/", "")
+      .split("/");
+  }
+
+  function _zoneWithoutPrefix(timezone) {
+    const parts = _formatTimezone(timezone);
+    return parts[1] || parts[0];
+  }
+
+  function _applyZoneToDateTime(dateTime, timezone) {
+    return moment.tz(dateTime, timezone).utc();
+  }
+
+  function _translateCalendarKey(time, key) {
+    const translated = I18n.t(`discourse_local_dates.relative_dates.${key}`, {
+      time: "LT"
+    });
 
-      if (utcDateTime < utc) {
-        // if event is in the past we want to bump it no next occurrence when
-        // recurring is set
-        if (options.recurring) {
-          utcDateTime = _applyRecurrence(utcDateTime, options.recurring);
+    if (time) {
+      return translated
+        .split("LT")
+        .map(w => `[${w}]`)
+        .join("LT");
+    } else {
+      return `[${translated.replace(" LT", "")}]`;
+    }
+  }
+
+  function _calendarFormats(time) {
+    return {
+      sameDay: _translateCalendarKey(time, "today"),
+      nextDay: _translateCalendarKey(time, "tomorrow"),
+      lastDay: _translateCalendarKey(time, "yesterday"),
+      sameElse: "L"
+    };
+  }
+
+  function _isEqualZones(timezoneA, timezoneB) {
+    return (
+      moment.tz(timezoneA).utcOffset() === moment.tz(timezoneB).utcOffset()
+    );
+  }
+
+  function _applyFormatting(dateTime, displayedTimezone, options) {
+    const sameTimezone = _isEqualZones(displayedTimezone, moment.tz.guess());
+    const inCalendarRange = dateTime.isBetween(
+      moment().subtract(2, "days"),
+      moment().add(2, "days")
+    );
+
+    if (options.calendar && inCalendarRange) {
+      if (sameTimezone) {
+        if (options.time) {
+          dateTime = dateTime.calendar(null, _calendarFormats(options.time));
         } else {
-          $element.addClass("past");
+          dateTime = dateTime.calendar(null, _calendarFormats(null));
         }
+      } else {
+        dateTime = dateTime.format(options.format);
+        dateTime = dateTime.replace("TZ", "");
+        dateTime = `${dateTime} (${_zoneWithoutPrefix(displayedTimezone)})`;
       }
+    } else {
+      if (options.time) {
+        dateTime = dateTime.format(options.format);
 
-      // once we have the correct UTC date we want
-      // we adjust it to watching user timezone
-      const adjustedDateTime = utcDateTime.tz(displayedTimezone);
-
-      const previews = _generatePreviews(
-        adjustedDateTime.clone(),
-        displayedTimezone,
-        options
-      );
-      const textPreview = _generateTextPreview(previews);
-      const htmlPreview = _generateHtmlPreview(previews);
-
-      const formatedDateTime = _applyFormatting(
-        adjustedDateTime,
-        displayedTimezone,
-        options
-      );
-
-      const $dateTemplate = `
-        <span>
-          <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"></span>
-        </span>
-      `;
-
-      $element
-        .html($dateTemplate)
-        .attr("title", textPreview)
-        .attr("data-html-tooltip", `<div class="previews">${htmlPreview}</div>`)
-        .addClass("cooked-date")
-        .find(".relative-time")
-        .text(formatedDateTime);
-
-      if (repeat) {
-        this.timeout = setTimeout(
-          () => processElement($element, options),
-          10000
-        );
-      }
-    };
-
-    const _formatTimezone = timezone =>
-      timezone
-        .replace("_", " ")
-        .replace("Etc/", "")
-        .split("/");
-
-    const _zoneWithoutPrefix = timezone => {
-      const parts = _formatTimezone(timezone);
-      return parts[1] || parts[0];
-    };
-
-    const _applyZoneToDateTime = (dateTime, timezone) => {
-      return moment.tz(dateTime, timezone).utc();
-    };
-
-    const _calendarFormats = time => {
-      const _translate = key => {
-        const translated = I18n.t(
-          `discourse_local_dates.relative_dates.${key}`,
-          {

GitHub