PageSourceSearch

https://glct.org.uk/script.js?v=portalforms1

js glct.org.uk collected 2026-10-04 02:08:55 UTC 5,433 bytes, 136 lines download raw bytes

1const toggle = document.querySelector(".menu-toggle");
2const nav = document.querySelector(".site-nav");
3
4toggle?.addEventListener("click", () => {
5  const open = nav.classList.toggle("open");
6  toggle.setAttribute("aria-expanded", open);
7});
8
9document.querySelectorAll(".site-nav a").forEach((a) =>
10  a.addEventListener("click", () => {
11    nav.classList.remove("open");
12    toggle?.setAttribute("aria-expanded", "false");
13  }),
14);
15
16const year = document.getElementById("year");
17if (year) year.textContent = new Date().getFullYear();
18
19// The newsletter footer is repeated across the main site and legacy archive.
20// Add the consent control to older archived copies that pre-date the new markup.
21document.querySelectorAll('form[name="newsletter"]').forEach((form) => {
22  if (form.querySelector('[name="marketing-consent"]')) return;
23  const label = document.createElement("label");
24  label.className = "newsletter-consent";
25  const checkbox = document.createElement("input");
26  checkbox.type = "checkbox";
27  checkbox.name = "marketing-consent";
28  checkbox.value = "yes";
29  checkbox.required = true;
30  const text = document.createElement("span");
31  text.textContent =
32    "I consent to GLCT using my email address to send occasional news and event updates.";
33  label.append(checkbox, text);
34  form.append(label);
35});
36
37(function () {
38  const select = document.querySelector('select[name="enquiry-type"]');
39  if (!select) return;
40  const type = new URLSearchParams(window.location.search).get("type");
41  const map = {
42    support: "Requesting support",
43    volunteer: "Volunteering",
44    fundraising: "Fundraising",
45    business: "Corporate partnership",
46    policy: "Policy / governance request",
47  };
48  if (type && map[type]) select.value = map[type];
49})();
50
51// Keep the public events diary aligned with the trustee-managed diary.
52(async function () {
53  const cards = [...document.querySelectorAll("[data-events-diary] [data-diary-id]")];
54  if (!cards.length) return;
55  const formatDate = (start, end) => {
56    const options = { day: "numeric", month: "long", year: "numeric" };
57    const first = new Date(`${start}T12:00:00`).toLocaleDateString("en-GB", options);
58    if (!end) return first;
59    const last = new Date(`${end}T12:00:00`);
60    const startDate = new Date(`${start}T12:00:00`);
61    if (startDate.getMonth() === last.getMonth() && startDate.getFullYear() === last.getFullYear()) {
62      return `${startDate.getDate()}–${last.toLocaleDateString("en-GB", options)}`;
63    }
64    return `${first}–${last.toLocaleDateString("en-GB", options)}`;
65  };
66  try {
67    const response = await fetch("/api/events-live", { headers: { Accept: "application/json" } });
68    if (!response.ok) return;
69    const data = await response.json();
70    const byId = new Map((data.items || []).map((item) => [item.id, item]));
71    for (const card of cards) {
72      const item = byId.get(card.dataset.diaryId);
73      if (!item) continue;
74      card.dataset.diaryActive = String(item.active !== false);
75      card.hidden =
76        card.dataset.diaryActive === "false" ||
77        card.dataset.projectActive === "false";
78      const date = card.querySelector("[data-diary-date]");
79      const name = card.querySelector("[data-diary-name]");
80      const location = card.querySelector("[data-diary-location]");
81      const description = card.querySelector("[data-diary-description]");
82      if (date) {
83        date.textContent = formatDate(item.startDate, item.endDate);
84        date.dateTime = item.startDate;
85      }
86      if (name) {
87        let displayName = item.name;
88        if (name.dataset.diaryShortName === "true" && item.location) {
89          displayName = displayName.replace(/\s+at\s+.+$/i, "");
90        }
91        name.textContent = displayName;
92      }
93      if (location) {
94        location.textContent = item.location || "";
95        location.hidden = !item.location;
96      }
97      if (description) description.textContent = item.description;
98    }
99  } catch (_error) {
100    // Static diary copy remains available if the API is unavailable.
101  }
102})();
103
104// Keep the three signature-project cards current without turning them into a 
104news feed.
105(async function () {
106  const cards = [
107    ...document.querySelectorAll("[data-signature-projects] [data-project-id]"),
108  ];
109  if (!cards.length) return;
110  try {
111    const res = await fetch("/api/projects-live", {
112      headers: { Accept: "application/json" },
113    });
114    if (!res.ok) return;
115    const data = await res.json();
116    const items = Array.isArray(data.items) ? data.items : [];
117    const byId = new Map(items.map((item) => [item.id, item]));
118    for (const card of cards) {
119      const item = byId.get(card.dataset.projectId);
120      if (!item) continue;
121      card.dataset.projectActive = String(item.active !== false);
122      card.hidden =
123        card.dataset.diaryActive === "false" ||
124        card.dataset.projectActive === "false";
125      const timing = card.querySelector("[data-project-timing]");
126      const title = card.querySelector("[data-project-title]");
127      const description = card.querySelector("[data-project-description]");
128      if (timing && item.timing) timing.textContent = item.timing;
129      if (title && item.title) title.textContent = item.title;
130      if (description && item.description)
131        description.textContent = item.description;
132    }
133  } catch (_err) {
134    // The static copy in index.html remains visible if the API is unavailable.
135  }
136})();

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.