1 $(document).on("turbo:frame-load", function () {
 
   2   const heatmap = $(".heatmap").removeClass("d-none").addClass("d-grid");
 
   3   const weekInfo = getWeekInfo();
 
   4   const maxPerDay = heatmap.data("max-per-day");
 
   5   const weekdayLabels = heatmap.find("[data-weekday]");
 
   7   let previousMonth = null;
 
   9   for (const day of weekdayLabels) {
 
  11     const weekday = $day.data("weekday");
 
  12     if (weekday < weekInfo.firstDay % 7) {
 
  13       $day.insertAfter(weekdayLabels.last());
 
  15     const weekdayRow = getWeekdayRow(weekday);
 
  16     if (weekdayRow % 2 === 0) $day.remove();
 
  17     $day.css("grid-area", weekdayRow + " / 1");
 
  20   for (const day of heatmap.find("[data-date]")) {
 
  22     const date = new Date($day.data("date"));
 
  23     if (date.getUTCDay() === weekInfo.firstDay % 7) {
 
  25       const currentMonth = getMonthOfThisWeek(date);
 
  26       if (previousMonth === null) {
 
  27         previousMonth = currentMonth;
 
  28         heatmap.find(`[data-month]:has( ~ [data-month="${previousMonth}"])`).remove();
 
  29         heatmap.find("[data-month]").first().css("grid-column-start", 2);
 
  31       if (previousMonth % 12 !== currentMonth % 12) {
 
  32         heatmap.find(`[data-month="${previousMonth}"]`).css("grid-column-end", weekColumn);
 
  34         heatmap.find(`[data-month="${previousMonth}"]`).css("grid-column-start", weekColumn);
 
  37     if (weekColumn === 1) {
 
  41     const count = $day.data("count") ?? 0;
 
  42     const tooltipText = getTooltipText(date, count);
 
  44       .css("grid-area", getWeekdayRow(date.getUTCDay()) + " / " + weekColumn)
 
  45       .attr("aria-label", tooltipText)
 
  49         delay: { show: 0, hide: 0 }
 
  52       .css("opacity", Math.sqrt(count / maxPerDay));
 
  54   heatmap.find(`[data-month="${previousMonth}"] ~ [data-month]`).remove();
 
  55   heatmap.find("[data-month]").last().css("grid-column-end", weekColumn + 1);
 
  57   function getMonthOfThisWeek(date) {
 
  58     const nextDate = new Date(date);
 
  59     nextDate.setUTCDate(date.getUTCDate() + weekInfo.minimalDays - 1);
 
  60     return nextDate.getUTCMonth() + 1;
 
  63   function getWeekdayRow(weekday) {
 
  64     return ((weekday - weekInfo.firstDay + 7) % 7) + 2;
 
  67   function getTooltipText(date, value) {
 
  68     const localizedDate = OSM.i18n.l("date.formats.heatmap", date);
 
  71       return OSM.i18n.t("javascripts.heatmap.tooltip.contributions", { count: value, date: localizedDate });
 
  74     return OSM.i18n.t("javascripts.heatmap.tooltip.no_contributions", { date: localizedDate });
 
  77   function getWeekInfo() {
 
  78     const weekInfo = { firstDay: 1, minimalDays: 4 }; // ISO 8601
 
  79     const locale = new Intl.Locale(OSM.i18n.locale);
 
  80     return { ...weekInfo, ...locale.weekInfo, ...locale.getWeekInfo?.() };