PageSourceSearch

https://grigsi.com/js/connect-mode-duration-labels.js?v=6

js grigsi.com collected 2026-10-02 01:32:58 UTC 7,324 bytes, 191 lines download raw bytes

1"use strict";
2
3(function (global) {
4  const DEFAULT_TEMP_HOURS = 24;
5  const DEFAULT_BUSINESS_DAYS = 30;
6  /** User-facing copy for relation_kind === "one_time" (session-scoped, not a 24h timer). */
7  const ONE_TIME_MODE_TITLE = "One-time session";
8  const ONE_TIME_MODE_SUBTITLE = "Until session ends";
9  const ONE_TIME_PANEL_META =
10    "Guest access for this session only. It ends when you or they leave the Space.";
11  const ONE_TIME_SUMMARY = ONE_TIME_MODE_TITLE + " · until session ends";
12  const ACTION_MODE_TITLE = "Actions";
13  /** User-facing copy for relation_kind === "fixed_term" (access until a set date). */
14  const FIXED_TERM_MODE_TITLE = "Fixed-term";
15  const FIXED_TERM_PANEL_META =
16    "Access until the date you choose. Files and history for ongoing work with a clear end.";
17  const FIXED_TERM_SUMMARY_PREFIX = FIXED_TERM_MODE_TITLE + " · ";
18  const ACTION_MODE_SUBTITLE = "Unlimited";
19  const ACTION_SUMMARY = ACTION_MODE_TITLE + " · unlimited";
20
21  let state = { tempHours: DEFAULT_TEMP_HOURS, businessDays: DEFAULT_BUSINESS_DAYS };
22
23  function formatHoursLabel(hours) {
24    const n = Math.max(1, Math.round(Number(hours) || DEFAULT_TEMP_HOURS));
25    return n === 1 ? "1 hour" : n + " hours";
26  }
27
28  function formatDaysLabel(days) {
29    const n = Math.max(1, Math.round(Number(days) || DEFAULT_BUSINESS_DAYS));
30    return n === 1 ? "1 day" : n + " days";
31  }
32
33  function readTempHoursFromEl(el) {
34    const h = Number(el && el.value);
35    return Number.isFinite(h) && h > 0 ? h : DEFAULT_TEMP_HOURS;
36  }
37
38  function effectiveTempHours(hoursId, untilId) {
39    const hoursEl = hoursId ? document.getElementById(hoursId) : null;
40    const untilEl = untilId ? document.getElementById(untilId) : null;
41    const until = untilEl && untilEl.value ? new Date(untilEl.value).getTime() : 0;
42    if (Number.isFinite(until) && until > Date.now()) {
43      return Math.max(1, Math.round((until - Date.now()) / (60 * 60 * 1000)));
44    }
45    return readTempHoursFromEl(hoursEl);
46  }
47
48  function businessDaysFromDateEl(el) {
49    if (!el || !el.value) return DEFAULT_BUSINESS_DAYS;
50    const until = new Date(el.value + "T23:59:59").getTime();
51    if (!Number.isFinite(until) || until <= Date.now()) return DEFAULT_BUSINESS_DAYS;
52    return Math.max(1, Math.round((until - Date.now()) / (24 * 60 * 60 * 1000)));
53  }
54
55  function setModeButtonSubtitle(btn, text) {
56    const span = btn.querySelector(":scope > span");
57    if (span) span.textContent = text;
58  }
59
60  function setModeButtonTitle(btn, text) {
61    const strong = btn.querySelector(":scope > strong");
62    if (strong) {
63      const count = strong.querySelector(".space-spacebook-filter-count");
64      if (count) {
65        const countHtml = count.outerHTML;
66        strong.textContent = text + " ";
67        strong.insertAdjacentHTML("beforeend", countHtml);
68      } else {
69        strong.textContent = text;
70      }
71    }
72  }
73
74  function applyAccessModeButtonLabels() {
75    document.querySelectorAll('[data-access-mode="one_time"]').forEach((btn) => {
76      btn.textContent = ONE_TIME_MODE_TITLE;
77    });
78    document.querySelectorAll('[data-access-mode="action"]').forEach((btn) => {
79      btn.textContent = ACTION_MODE_TITLE;
80    });
81  }
82
83  function applyToDom() {
84    const bizLabel = formatDaysLabel(state.businessDays);
85    document.querySelectorAll('[data-rel-mode="one_time"]').forEach((btn) => {
86      setModeButtonTitle(btn, ONE_TIME_MODE_TITLE);
87      setModeButtonSubtitle(btn, ONE_TIME_MODE_SUBTITLE);
88    });
89    document.querySelectorAll('[data-rel-mode="fixed_term"]').forEach((btn) => {
90      setModeButtonSubtitle(btn, bizLabel);
91    });
92    document.querySelectorAll('[data-rel-mode="action"]').forEach((btn) => {
93      setModeButtonTitle(btn, ACTION_MODE_TITLE);
94      setModeButtonSubtitle(btn, ACTION_MODE_SUBTITLE);
95    });
96    document.querySelectorAll('[data-spacebook-filter="action"]').forEach((btn) => {
97      setModeButtonTitle(btn, ACTION_MODE_TITLE);
98      const sub = btn.querySelector(":scope > span");
99      if (sub) sub.textContent = ACTION_MODE_SUBTITLE;
100    });
101    document.querySelectorAll('[data-spacebook-filter="one_time"]').forEach((btn) => {
102      setModeButtonTitle(btn, ONE_TIME_MODE_TITLE);
103      const sub = btn.querySelector(":scope > span");
104      if (sub) sub.textContent = ONE_TIME_MODE_SUBTITLE;
105    });
106    applyAccessModeButtonLabels();
107    document.querySelectorAll('[data-spacebook-filter="fixed_term"]').forEach((btn) => {
108      const sub = btn.querySelector(":scope > span");
109      if (sub) sub.textContent = bizLabel;
110    });
111    try {
112      global.dispatchEvent(new CustomEvent("grigsi-connect-mode-labels"));
113    } catch (_) {}
114  }
115
116  function apply(partial) {
117    if (partial && typeof partial.tempHours === "number") state.tempHours = partial.tempHours;
118    if (partial && typeof partial.businessDays === "number") state.businessDays = partial.businessDays;
119    applyToDom();
120  }
121
122  function syncTempFromPair(hoursId, untilId) {
123    apply({ tempHours: effectiveTempHours(hoursId, untilId) });
124  }
125
126  function syncBusinessFromDateInput(dateId) {
127    const el = dateId ? document.getElementById(dateId) : null;
128    apply({ businessDays: businessDaysFromDateEl(el) });
129  }
130
131  const TEMP_BINDINGS = [
132    { hoursId: "rel-temp-hours", untilId: "rel-temp-until" },
133    { hoursId: "space-rel-temp-hours", untilId: "space-rel-temp-until" },
134    { hoursId: "space-access-temp-hours", untilId: "space-access-temp-until" },
135  ];
136
137  const BUSINESS_BINDINGS = ["rel-business-until", "space-rel-business-until", "space-access-business-until"];
138
139  function wire() {
140    TEMP_BINDINGS.forEach(({ hoursId, untilId }) => {
141      const onTemp = () => syncTempFromPair(hoursId, untilId);
142      const hoursEl = document.getElementById(hoursId);
143      const untilEl = document.getElementById(untilId);
144      hoursEl?.addEventListener("input", onTemp);
145      hoursEl?.addEventListener("change", onTemp);
146      untilEl?.addEventListener("input", onTemp);
147      untilEl?.addEventListener("change", onTemp);
148    });
149    BUSINESS_BINDINGS.forEach((dateId) => {
150      const onBiz = () => syncBusinessFromDateInput(dateId);
151      const el = document.getElementById(dateId);
152      el?.addEventListener("input", onBiz);
153      el?.addEventListener("change", onBiz);
154    });
155    const firstTemp = TEMP_BINDINGS.find((b) => document.getElementById(b.hoursId));
156    if (firstTemp) syncTempFromPair(firstTemp.hoursId, firstTemp.untilId);
157    const firstBiz = BUSINESS_BINDINGS.find((id) => document.getElementById(id));
158    if (firstBiz) syncBusinessFromDateInput(firstBiz);
159    else apply({});
160  }
161
162  global.GriGsiConnectModeLabels = {
163    DEFAULT_TEMP_HOURS,
164    DEFAULT_BUSINESS_DAYS,
165    ONE_TIME_MODE_TITLE,
166    ONE_TIME_MODE_SUBTITLE,
167    ONE_TIME_PANEL_META,
168    ONE_TIME_SUMMARY,
169    FIXED_TERM_MODE_TITLE,
170    FIXED_TERM_PANEL_META,
171    FIXED_TERM_SUMMARY_PREFIX,
172    ACTION_MODE_TITLE,
173    ACTION_MODE_SUBTITLE,
174    ACTION_SUMMARY,
175    formatHoursLabel,
176    formatDaysLabel,
177    effectiveTempHours,
178    businessDaysFromDateEl,
179    getState: () => ({ ...state }),
180    apply,
181    syncTempFromPair,
182    syncBusinessFromDateInput,
183    wire,
184  };
185
186  if (document.readyState === "loading") {
187    document.addEventListener("DOMContentLoaded", wire);
188  } else {
189    wire();
190  }
191})(typeof window !== "undefined" ? window : globalThis);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.