PageSourceSearch

https://grigsi.com/js/sendi-access-settings-ui.js?v=1

js grigsi.com collected 2026-09-24 14:45:35 UTC 13,704 bytes, 360 lines download raw bytes

1"use strict";
2
3/** Access settings modal — mode picker, cap link apply/revoke. */
4(function (global) {
5  let ctx = null;
6  let wired = false;
7  let accessDraftMode = "one_time";
8  let accessDraftAction = "bundle";
9  const ACCESS_PANEL_IDS = ["one_time", "action", "fixed_term", "trusted"];
10
11  function c() {
12    return ctx && typeof ctx === "object" ? ctx : {};
13  }
14
15  function ax(v, fb) {
16    const fn = c().ax;
17    return fn ? fn(v, fb) : String(v || fb || "trusted");
18  }
19
20  function axIs(a, b) {
21    const fn = c().axIs;
22    return fn ? fn(a, b) : ax(a) === ax(b);
23  }
24
25  function AX() {
26    const fn = c().AX;
27    return fn ? fn() : null;
28  }
29
30  function policy() {
31    const g = c().getPolicy;
32    return g && typeof g === "function" ? g() || {} : {};
33  }
34
35  function setPolicy(p) {
36    if (c().setPolicy) c().setPolicy(p);
37  }
38
39  function readSpaceAccessGuestPerms() {
40    const GP = global.GriGsiCapGuestPerms;
41    if (!GP || !GP.readCheckedPerms) return [];
42    return GP.readCheckedPerms("[data-access-guest-perm]");
43  }
44
45  function applyGuestPermsToCheckboxes(perms) {
46    const GP = global.GriGsiCapGuestPerms;
47    const root = document.getElementById("space-access-guest-perms");
48    if (GP && GP.applyPermsToGroup && root) {
49      GP.applyPermsToGroup(root, perms);
50      return;
51    }
52    const set = new Set(GP ? GP.normalizeCapPerms(perms) : []);
53    document.querySelectorAll("[data-access-guest-perm]").forEach((el) => {
54      const key = String(el.getAttribute("data-access-guest-perm") || "").toLowerCase();
55      if (key) el.checked = set.has(key);
56    });
57  }
58
59  function syncAccessGuestPermsPanelVisible() {
60    const box = document.getElementById("space-access-guest-perms");
61    if (!box) return;
62    const mode = ax(accessDraftMode || policy().mode, "trusted");
63    const show = AX() ? !AX().is(mode, AX().IDS.TRUSTED) : mode !== "trusted";
64    box.classList.toggle("hidden", !show);
65    box.hidden = !show;
66    box.setAttribute("aria-hidden", show ? "false" : "true");
67  }
68
69  function setAccessModeUi(mode) {
70    accessDraftMode = ax(mode, "one_time");
71    document.querySelectorAll("[data-access-mode]").forEach((btn) => {
72      const on = axIs(btn.getAttribute("data-access-mode"), accessDraftMode);
73      btn.classList.toggle("is-on", on);
74      btn.setAttribute("aria-checked", on ? "true" : "false");
75    });
76    (AX()?.ALL_IDS || ACCESS_PANEL_IDS).forEach((name) => {
77      const panel = document.getElementById("space-access-panel-" + name);
78      if (!panel) return;
79      const show = axIs(name, accessDraftMode);
80      panel.classList.toggle("hidden", !show);
81      panel.setAttribute("aria-hidden", show ? "false" : "true");
82    });
83    syncAccessGuestPermsPanelVisible();
84  }
85
86  function setAccessActionUi(action) {
87    const act = String(action || "chat").toLowerCase();
88    accessDraftAction = act === "all" ? "bundle" : act;
89    document.querySelectorAll("[data-access-action]").forEach((btn) => {
90      const on = btn.getAttribute("data-access-action") === accessDraftAction;
91      btn.classList.toggle("is-on", on);
92    });
93  }
94
95  function initAccessDateInputs() {
96    const now = Date.now();
97    const tempUntil = new Date(now + 24 * 60 * 60 * 1000);
98    const tempInput = document.getElementById("space-access-temp-until");
99    if (tempInput && !tempInput.value) {
100      const localIso = new Date(tempUntil.getTime() - tempUntil.getTimezoneOffset() * 60000)
101        .toISOString()
102        .slice(0, 16);
103      tempInput.value = localIso;
104    }
105    const bizUntil = new Date(now + 30 * 24 * 60 * 60 * 1000);
106    const bizInput = document.getElementById("space-access-business-until");
107    if (bizInput && !bizInput.value) {
108      const yyyy = bizUntil.getFullYear();
109      const mm = String(bizUntil.getMonth() + 1).padStart(2, "0");
110      const dd = String(bizUntil.getDate()).padStart(2, "0");
111      bizInput.value = yyyy + "-" + mm + "-" + dd;
112    }
113  }
114
115  async function open() {
116    const modal = document.getElementById("access-settings-modal");
117    if (!modal) return;
118    const guestPerm = c().guestHasDelegatePerm;
119    const toast = c().showToast;
120    if (typeof guestPerm === "function" && !guestPerm("settings")) {
121      if (typeof toast === "function") {
122        toast("You do not have permission to change access settings for this Space.", "warning");
123      }
124      return;
125    }
126    modal.classList.add("active");
127    const urlHasCap = c().urlHasCapParam;
128    try {
129      if (urlHasCap && urlHasCap(global.location.href)) {
130        if (c().hydrateAccessPolicyFromUrl) await c().hydrateAccessPolicyFromUrl();
131        if (c().loadCapPayloadForLimits) await c().loadCapPayloadForLimits();
132        if (c().bindActionLimitContext) c().bindActionLimitContext();
133      } else if (c().ensureCapInviteLinkForHostPolicy) {
134        await c().ensureCapInviteLinkForHostPolicy();
135      }
136    } catch (_) {}
137    initAccessDateInputs();
138    if (global.GriGsiConnectModeLabels) {
139      global.GriGsiConnectModeLabels.syncTempFromPair("space-access-temp-hours", "space-access-temp-until");
140      global.GriGsiConnectModeLabels.syncBusinessFromDateInput("space-access-business-until");
141    }
142    const p = policy();
143    setAccessModeUi(p.mode || "one_time");
144    setAccessActionUi(p.action || "bundle");
145    applyGuestPermsToCheckboxes(p.guest_perms || p.cap_perms || []);
146    syncAccessGuestPermsPanelVisible();
147    const summary = c().accessSummary;
148    const currentEl = document.getElementById("space-access-current");
149    const linkEl = document.getElementById("space-access-link");
150    if (currentEl && typeof summary === "function") {
151      currentEl.textContent = "Current: " + summary(p);
152    }
153    const joinLink = c().getJoinLink ? c().getJoinLink() : "";
154    if (linkEl) linkEl.value = String(p.link || joinLink || "");
155  }
156
157  function close() {
158    const modal = document.getElementById("access-settings-modal");
159    if (modal) modal.classList.remove("active");
160  }
161
162  async function applyFromModal() {
163    const SB = global.GriGsiSpaceBook || global.GriGsiConnectLocalMode;
164    const toast = c().showToast;
165    if (!SB || !SB.createLocalLink) {
166      if (typeof toast === "function") toast("Access policy is unavailable on this device.", "warning");
167      return;
168    }
169    const getQuality = c().getActiveSpaceVideoQuality;
170    const buildJoin = c().buildJoinLinkString;
171    let nextLink =
172      typeof buildJoin === "function" ? buildJoin(getQuality ? getQuality() : "default") : "";
173    let nextExpires = null;
174    let nextCapJti = "";
175    const mode = ax(accessDraftMode, "trusted");
176    const guestPerms = readSpaceAccessGuestPerms();
177    const scopeFor = c().scopeForAccessAction;
178    const withMod = c().withShareModule;
179    const modFor = c().moduleForAccessAction;
180    const readTemp = c().readAccessTempTtlMs;
181    const readBiz = c().readAccessBusinessTtlMs;
182    const secretFn = c().getSpaceSecret;
183    const secret = secretFn && typeof secretFn === "function" ? secretFn() : "";
184
185    if (axIs(mode, "action")) {
186      const scope = scopeFor ? scopeFor(accessDraftAction) : "action:join_once";
187      const link = await SB.createLocalLink(secret, {
188        kind: "action",
189        scope,
190        ttl_ms: 24 * 60 * 60 * 1000,
191        perms: guestPerms,
192      });
193      if (!link || !link.ok || !link.url) {
194        if (typeof toast === "function") toast("Could not create action link.", "warning");
195        return;
196      }
197      const draftAct = String(accessDraftAction || "chat").toLowerCase();
198      nextLink =
199        draftAct === "bundle" || draftAct === "all"
200          ? link.url
201          : withMod
202            ? withMod(link.url, modFor ? modFor(draftAct) : "chat")
203            : link.url;
204      nextExpires = Number(link.expires_at) || null;
205      nextCapJti = String(link.jti || "");
206    } else if (axIs(mode, "one_time")) {
207      const link = await SB.createLocalLink(secret, {
208        kind: "temporary",
209        ttl_ms: readTemp ? readTemp() : 15 * 60 * 1000,
210        perms: guestPerms,
211      });
212      if (!link || !link.ok || !link.url) {
213        if (typeof toast === "function") toast("Could not create one-time link.", "warning");
214        return;
215      }
216      nextLink = link.url;
217      nextExpires = Number(link.expires_at) || null;
218      nextCapJti = String(link.jti || "");
219    } else if (axIs(mode, "fixed_term")) {
220      const link = await SB.createLocalLink(secret, {
221        kind: "business",
222        ttl_ms: readBiz ? readBiz() : 30 * 24 * 60 * 60 * 1000,
223        perms: guestPerms,
224      });
225      if (!link || !link.ok || !link.url) {
226        if (typeof toast === "function") toast("Could not create fixed-term link.", "warning");
227        return;
228      }
229      nextLink = link.url;
230      nextExpires = Number(link.expires_at) || null;
231      nextCapJti = String(link.jti || "");
232    }
233
234    const nextPolicy = {
235      mode,
236      action: axIs(mode, "action") ? accessDraftAction : accessDraftAction || "bundle",
237      guest_perms: guestPerms,
238      cap_perms: guestPerms,
239      expires_at: nextExpires,
240      cap_jti: nextCapJti,
241      source: "space_modal",
242      link: nextLink,
243    };
244    setPolicy(nextPolicy);
245    if (c().setJoinLink) c().setJoinLink(nextLink);
246
247    const summary = c().accessSummary;
248    const currentEl = document.getElementById("space-access-current");
249    const linkEl = document.getElementById("space-access-link");
250    if (currentEl && typeof summary === "function") {
251      currentEl.textContent = "Current: " + summary(nextPolicy);
252    }
253    if (linkEl) linkEl.value = nextLink;
254    if (c().renderAccessChip) c().renderAccessChip();
255    if (c().saveAccessPolicyLocal) c().saveAccessPolicyLocal();
256    if (c().clearAccessLimitExhaustedSignaling) c().clearAccessLimitExhaustedSignaling();
257    if (c().startAccessPolicyExpiryWatch) c().startAccessPolicyExpiryWatch();
258    if (typeof toast === "function") toast("Access policy updated. Share the new link.", "success");
259  }
260
261  async function revokeCurrentCap() {
262    const SB = global.GriGsiSpaceBook || global.GriGsiConnectLocalMode;
263    const p = policy();
264    const jti = String(p.cap_jti || "");
265    const toast = c().showToast;
266    const signal = c().signalAccessLimitExhausted;
267    if (!SB || !SB.markCapJtiConsumed || !jti) {
268      if (typeof toast === "function") toast("Current link has no revocable cap.", "warning");
269      return;
270    }
271    try {
272      await SB.markCapJtiConsumed(jti);
273      const next = { ...p, cap_jti: "", expires_at: Date.now() };
274      setPolicy(next);
275      if (c().saveAccessPolicyLocal) c().saveAccessPolicyLocal();
276      if (c().renderAccessChip) c().renderAccessChip();
277      const currentEl = document.getElementById("space-access-current");
278      if (currentEl) currentEl.textContent = "Current: revoked cap (create a new link)";
279      if (typeof signal === "function") signal({ reason: "revoked" });
280    } catch (_) {
281      if (typeof toast === "function") toast("Could not revoke this cap link.", "warning");
282    }
283  }
284
285  function wireControls(chipEl) {
286    if (wired) return;
287    wired = true;
288    const modal = document.getElementById("access-settings-modal");
289    document.getElementById("close-access-settings")?.addEventListener("click", () => close());
290    modal?.addEventListener("click", (e) => {
291      if (e.target === modal) close();
292    });
293    function onChipActivate(e) {
294      e.preventDefault();
295      e.stopPropagation();
296      void open();
297    }
298    let lastTouchAt = 0;
299    chipEl?.addEventListener(
300      "touchend",
301      (e) => {
302        lastTouchAt = Date.now();
303        onChipActivate(e);
304      },
305      { passive: false }
306    );
307    chipEl?.addEventListener("click", (e) => {
308      if (Date.now() - lastTouchAt < 500) {
309        e.preventDefault();
310        e.stopPropagation();
311        return;
312      }
313      onChipActivate(e);
314    });
315    document.querySelectorAll("[data-access-mode]").forEach((btn) => {
316      btn.addEventListener("click", () => setAccessModeUi(btn.getAttribute("data-access-mode") || "one_time"));
317    });
318    document.querySelectorAll("[data-access-action]").forEach((btn) => {
319      btn.addEventListener("click", () => setAccessActionUi(btn.getAttribute("data-access-action") || "chat"));
320    });
321    document.getElementById("space-access-guest-perms")?.addEventListener("grigsi-guest-perms-ch
321ange", () => {
322      syncAccessGuestPermsPanelVisible();
323    });
324    document.getElementById("btn-access-apply")?.addEventListener("click", () => void applyFromModal());
325    document.getElementById("btn-access-copy-link")?.addEventListener("click", async () => {
326      const linkEl = document.getElementById("space-access-link");
327      const val = String((linkEl && linkEl.value) || "").trim();
328      const toast = c().showToast;
329      if (!val) {
330        if (typeof toast === "function") toast("No generated link yet.", "warning");
331        return;
332      }
333      try {
334        await navigator.clipboard.writeText(val);
335        if (typeof toast === "function") toast("Access link copied.", "success");
336      } catch (_) {
337        if (typeof toast === "function") toast(val, "info");
338      }
339    });
340    document.getElementById("btn-access-revoke-current")?.addEventListener("click", () => void revokeCurrentCap());
341  }
342
343  function init(context) {
344    ctx = context && typeof context === "object" ? context : {};
345    const chip = c().getAccessChipEl ? c().getAccessChipEl() : document.getElementById("space-access-chip");
346    wireControls(chip);
347    return global.GriGsiSpaceAccessSettingsUi;
348  }
349
350  global.GriGsiSpaceAccessSettingsUi = {
351    init,
352    open,
353    close,
354    applyFromModal,
355    revokeCurrentCap,
356    setAccessModeUi,
357    setAccessActionUi,
358    syncAccessGuestPermsPanelVisible,
359  };
360})(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.