1(() => { 2 var __defProp = Object.defineProperty; 3 var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; 4 var __publicField = (obj, key, value) => { 5 __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); 6 return value; 7 }; 8 9
9// src/js/frontend/components/ScriptUnblocker.js 10 var ScriptUnblocker = class { 11 /** 12 * Unblock and execute all blocked scripts for a specific category slug. 13 * 14 * @param {string} category Category slug (e.g. 'functional', 'analytics', 'marketing', or custom slug). 15 */ 16 static unblockCategory(category) { 17 if (!category) { 18 return; 19 } 20 const selector = `script[data-category="${category}"]`; 21 const scripts = document.querySelectorAll(selector); 22 scripts.forEach((oldScript) => { 23 if (oldScript.classList.contains("sgc-activated")) { 24 return; 25 } 26 const mimeType = oldScript.getAttribute("type"); 27 if (mimeType && mimeType !== "text/plain") { 28 return; 29 } 30 oldScript.classList.add("sgc-activated"); 31 const newScript = document.createElement("script"); 32 newScript.type = "text/javascript"; 33 Array.from(oldScript.attributes).forEach((attr) => { 34 if (attr.name !== "type" && attr.name !== "data-src" && attr.name !== "data-sgc-src") { 35 newScript.setAttribute(attr.name, attr.value); 36 } 37 }); 38 const src = oldScript.getAttribute("src") || oldScript.getAttribute("data-src") || oldScript.getAttribute("data-sgc-src"); 39 if (src) { 40 newScript.src = src; 41 } else { 42 newScript.textContent = oldScript.textContent || oldScript.innerHTML; 43 } 44 document.head.appendChild(newScript); 45 }); 46 window.dataLayer = window.dataLayer || []; 47 window.dataLayer.push({ 48 event: "sgc_event_" + category 49 }); 50 document.dispatchEvent(new CustomEvent("sgc_enable_category", { detail: { category } })); 51 } 52 /** 53 * Unblock multiple categories. 54 * 55 * @param {string[]} categories List of category slugs. 56 */ 57 static unblockCategories(categories = []) { 58 if (!Array.isArray(categories)) { 59 return; 60 } 61 categories.forEach((cat) => { 62 this.unblockCategory(cat); 63 }); 64 document.dispatchEvent(new CustomEvent("sgc_all_scripts_fired", { detail: { categories } })); 65 } 66 }; 67 68
68// src/js/frontend/components/Consent.js 69 var Consent = class { 70 /** 71 * Get a browser cookie value by name. 72 * 73 * @param {string} name Cookie name. 74 * @returns {string|null} Cookie value or null if not found. 75 */ 76 static getCookie(name) { 77 const nameEQ = name + "="; 78 const cookies = document.cookie.split(";"); 79 for (let i = 0; i < cookies.length; i++) { 80 let c = cookies[i].trim(); 81 if (c.indexOf(nameEQ) === 0) { 82 return decodeURIComponent(c.substring(nameEQ.length, c.length)); 83 } 84 } 85 return null; 86 } 87 /** 88 * Set a browser cookie. 89 * 90 * @param {string} name Cookie name. 91 * @param {string} value Cookie value. 92 * @param {number} days Days until expiration. 93 */ 94 static setCookie(name, value, days = this.COOKIE_EXPIRY_DAYS) { 95 const date = /* @__PURE__ */ new Date(); 96 date.setTime(date.getTime() + days * 24 * 60 * 60 * 1e3); 97 const expires = "; expires=" + date.toUTCString(); 98 const secure = window.location.protocol === "https:" ? "; secure" : ""; 99 document.cookie = `${name}=${encodeURIComponent(value)}${expires}; path=/; SameSite=Lax${secure}`; 100 } 101 /** 102 * Check whether the user has already made a consent choice. 103 * 104 * @returns {boolean} 105 */ 106 static hasConsentStatus() { 107 return Boolean(this.getCookie(this.COOKIE_STATUS_KEY)); 108 } 109 /** 110 * Get the list of all currently consented category slugs. 111 * 112 * @returns {string[]} 113 */ 114 static getConsentedCategories() { 115 const raw = this.getCookie(this.COOKIE_CATEGORIES_KEY); 116 if (raw) { 117 try { 118 const parsed = JSON.parse(raw); 119 if (Array.isArray(parsed)) { 120 if (!parsed.includes("functional")) { 121 parsed.unshift("functional"); 122 } 123 return parsed; 124 } 125 } catch (e) { 126 } 127 } 128 return ["functional"]; 129 } 130 /** 131 * Check if a specific category is consented. 132 * 133 * @param {string} category Category slug. 134 * @returns {boolean} 135 */ 136 static hasConsent(category) { 137 if (category === "functional") { 138 return true; 139 } 140 return this.getConsentedCategories().includes(category); 141 } 142 /** 143 * Update document.body classes based on consented categories. 144 * 145 * @param {string[]} categories List of active category slugs. 146 */ 147 static updateBodyClasses(categories = []) { 148 if (typeof document === "undefined" || !document.body) { 149 return; 150 } 151 Array.from(document.body.classList).forEach((className) => { 152 if (className.startsWith("sgc-category-") || className === "sgc-consent-active") { 153 document.body.classList.remove(className); 154 } 155 }); 156 if (this.hasConsentStatus()) { 157 document.body.classList.add("sgc-consent-active"); 158 categories.forEach((cat) => { 159 document.body.classList.add("sgc-category-" + cat); 160 }); 161 } 162 } 163 /** 164 * Save consented categories, update body classes, execute matching scripts, and dispatch events. 165 * 166 * @param {string[]} categories List of consented category slugs. 167 */ 168 static setConsents(categories = []) { 169 const uniqueCategories = Array.from(/* @__PURE__ */ new Set(["functional", ...categories])); 170 this.setCookie(this.COOKIE_STATUS_KEY, "allow"); 171 this.setCookie(this.COOKIE_CATEGORIES_KEY, JSON.stringify(uniqueCategories)); 172 this.updateBodyClasses(uniqueCategories); 173 ScriptUnblocker.unblockCategories(uniqueCategories); 174 document.dispatchEvent(new CustomEvent("sgc_consent_change", { 175 detail: { categories: uniqueCategories } 176 })); 177 uniqueCategories.forEach((cat) => { 178 document.dispatchEvent(new CustomEvent("sgc_enable_category", { 179 detail: { category: cat } 180 })); 181 document.dispatchEvent(new CustomEvent("sgc_enable_category_" + cat, { 182 detail: { category: cat } 183 })); 184 }); 185 } 186 /** 187 * Accept all categories. 188 * 189 * @param {string[]} allCategories List of all available category slugs. 190 */ 191 static acceptAll(allCategories = []) { 192 this.setConsents(allCategories); 193 } 194 /** 195 * Accept only necessary (functional) cookies. 196 */ 197 static acceptNecessary() { 198 this.setConsents(["functional"]); 199 } 200 /** 201 * Save custom selected preferences. 202 * 203 * @param {string[]} selectedCategories Selected category slugs. 204 */ 205 static savePreferences(selectedCategories = []) { 206 this.setConsents(selectedCategories); 207 } 208 /** 209 * Initialize consent state on page load. 210 * If consent was previously given, immediately unblocks consented scripts and sets body classes. 211 */ 212 static init() { 213 if (this.hasConsentStatus()) { 214 const consented = this.getConsentedCategories(); 215 this.updateBodyClasses(consented); 216 ScriptUnblocker.unblockCategories(consented); 217 document.dispatchEvent(new CustomEvent("sgc_consent_change", { 218 detail: { categories: consented } 219 })); 220 consented.forEach((cat) => { 221 document.dispatchEvent(new CustomEvent("sgc_enable_category_" + cat, { 222 detail: { category: cat } 223 })); 224 }); 225 } else { 226 ScriptUnblocker.unblockCategory("functional"); 227 } 228 } 229 }; 230 __publicField(Consent, "COOKIE_STATUS_KEY", "sgc_consent_status"); 231 __publicField(Consent, "COOKIE_CATEGORIES_KEY", "sgc_consented_categories");
232 __publicField(Consent, "COOKIE_EXPIRY_DAYS", 365); 233 234
234// src/js/frontend/components/ConsentButton.js 235 var ConsentButton = class { 236 /** 237 * Get the button DOM element. 238 * 239 * @returns {HTMLElement|null} 240 */ 241 static getElement() { 242 return document.getElementById(this.BUTTON_ID); 243 } 244 static init() { 245 const btn = this.getElement(); 246 if (!btn) { 247 return; 248 } 249 if (Consent.hasConsentStatus()) { 250 this.show(btn); 251 } else { 252 this.hide(btn); 253 } 254 btn.addEventListener("click", (e) => { 255 e.preventDefault(); 256 Modal.show(void 0, true); 257 }); 258 } 259 /** 260 * Show the floating button. 261 * 262 * @param {HTMLElement} [btn] 263 */ 264 static show(btn = this.getElement()) { 265 if (btn) { 266 btn.classList.add("sgc-consent-button--visible"); 267 btn.style.display = "inline-flex"; 268 } 269 } 270 /** 271 * Hide the floating button. 272 * 273 * @param {HTMLElement} [btn] 274 */ 275 static hide(btn = this.getElement()) { 276 if (btn) { 277 btn.classList.remove("sgc-consent-button--visible"); 278 btn.style.display = "none"; 279 } 280 } 281 }; 282 __publicField(ConsentButton, "BUTTON_ID", "sgc-consent-button"); 283 284
284// src/js/frontend/components/Modal.js 285 var Modal = class { 286 static init() { 287 const modalEl = document.getElementById("sgc-modal"); 288 if (!modalEl) { 289 return; 290 } 291 const detailsEl = document.getElementById("sgc-modal-details"); 292 const btnAcceptAll = document.getElementById("sgc-btn-accept-all"); 293 const btnAcceptNecessary = document.getElementById("sgc-btn-accept-necessary"); 294 const btnManageSettings = document.getElementById("sgc-btn-manage-settings"); 295 const toggleInputs = modalEl.querySelectorAll(".sgc-toggle__input[data-category]"); 296 this.syncCheckboxes(modalEl); 297 if (!Consent.hasConsentStatus()) { 298 this.show(modalEl); 299 } else { 300 this.hide(modalEl); 301 } 302 if (btnAcceptAll) { 303 btnAcceptAll.addEventListener("click", (e) => { 304 e.preventDefault(); 305 const allCategories = ["functional"]; 306 modalEl.querySelectorAll("[data-category]").forEach((el) => { 307 const cat = el.getAttribute("data-category"); 308 if (cat && !allCategories.includes(cat)) { 309 allCategories.push(cat); 310 } 311 }); 312 Consent.acceptAll(allCategories); 313 this.hide(modalEl); 314 ConsentButton.show(); 315 }); 316 } 317 if (btnAcceptNecessary) { 318 btnAcceptNecessary.addEventListener("click", (e) => { 319 e.preventDefault(); 320 Consent.acceptNecessary(); 321 this.hide(modalEl); 322 ConsentButton.show(); 323 }); 324 } 325 if (btnManageSettings) { 326 btnManageSettings.addEventListener("click", (e) => { 327 e.preventDefault(); 328 if (!detailsEl) { 329 return; 330 } 331 const isDetailsVisible = detailsEl.classList.contains("sgc-modal__details--visible"); 332 if (!isDetailsVisible) { 333 detailsEl.classList.add("sgc-modal__details--visible"); 334 } else { 335 const selected = ["functional"]; 336 toggleInputs.forEach((input) => { 337 if (input.checked) { 338 const cat = input.getAttribute("data-category"); 339 if (cat && !selected.includes(cat)) { 340 selected.push(cat); 341 } 342 } 343 }); 344 Consent.savePreferences(selected); 345 this.hide(modalEl); 346 ConsentButton.show(); 347 } 348 }); 349 } 350 } 351 /** 352 * Sync modal checkbox states with currently consented categories. 353 * 354 * @param {HTMLElement} modalEl 355 */ 356 static syncCheckboxes(modalEl = document.getElementById("sgc-modal")) { 357 if (!modalEl) { 358 return; 359 } 360 const toggleInputs = modalEl.querySelectorAll(".sgc-toggle__input[data-category]"); 361 toggleInputs.forEach((input) => { 362 const category = input.getAttribute("data-category"); 363 input.checked = Consent.hasConsent(category); 364 }); 365 } 366 /** 367 * Hide modal overlay. 368 * 369 * @param {HTMLElement} modalEl 370 */ 371 static hide(modalEl = document.getElementById("sgc-modal")) { 372 if (modalEl) { 373 modalEl.classList.remove("sgc-modal-overlay--visible"); 374 modalEl.style.display = "none"; 375 } 376 } 377 /** 378 * Show modal overlay and optionally open details. 379 * 380 * @param {HTMLElement} modalEl 381 * @param {boolean} openDetails 382 */ 383 static show(modalEl = document.getElementById("sgc-modal"), openDetails = false) { 384 if (modalEl) { 385 this.syncCheckboxes(modalEl); 386 if (openDetails) { 387 const detailsEl = modalEl.querySelector("#sgc-modal-details"); 388 if (detailsEl) { 389 detailsEl.classList.add("sgc-modal__details--visible"); 390 } 391 } 392 modalEl.classList.add("sgc-modal-overlay--visible"); 393 modalEl.style.display = "flex"; 394 } 395 } 396 }; 397 398
398// src/js/frontend/components/Accordion.js 399 var Accordion = class { 400 static init(container = document) { 401 const accordionItems = container.querySelectorAll(".sgc-accordion__item"); 402 accordionItems.forEach((item) => { 403 const header = item.querySelector(".sgc-accordion__header"); 404 if (!header) { 405 return; 406 } 407 header.addEventListener("click", (e) => { 408 if (e.target.closest(".sgc-toggle") || e.target.tagName === "INPUT") { 409 return; 410 } 411 item.classList.toggle("sgc-accordion__item--open"); 412 }); 413 }); 414 } 415 }; 416 417
417// src/js/frontend.js 418 window.SGC = window.SGC || {}; 419 window.SGC.Consent = Consent; 420 window.SGC.ScriptUnblocker = ScriptUnblocker; 421 window.SGC.Modal = Modal; 422 window.SGC.Accordion = Accordion; 423 window.SGC.ConsentButton = ConsentButton; 424 window.SGC.hasConsent = (category) => Consent.hasConsent(category); 425 window.SGC.getConsents = () => Consent.getConsentedCategories(); 426 window.SGC.hasConsentStatus = () => Consent.hasConsentStatus(); 427 window.SGC.on = (category, callback) => { 428 if (typeof callback !== "function") { 429 return; 430 } 431 if (Consent.hasConsent(category)) { 432 callback(); 433 } else { 434 document.addEventListener("sgc_enable_category_" + category, callback, { once: true }); 435 } 436 }; 437 document.addEventListener("DOMContentLoaded", () => { 438 Consent.init(); 439 Modal.init(); 440 Accordion.init(); 441 ConsentButton.init(); 442 }); 443})();
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.