PageSourceSearch

https://gex-levels.com/assets/privacy-choices.js

js gex-levels.com collected 2026-10-02 01:30:30 UTC 7,238 bytes, 91 lines download raw bytes

1/* Consent is separate from login, checkout, contractual acceptance and the NDA. */
2(function () {
3  'use strict';
4  if (window.GEXPrivacy) return;
5  var KEY = 'gex_privacy_choices_v1', TTL = 180 * 86400000;
6  var defaults = { analytics: false, marketing: false, referral: false };
7  var current = null, panel, trigger, returnFocus;
8  var DISMISSED = 'gex_privacy_dismissed_v1';
9  function read() {
10    try {
11      var x = JSON.parse(localStorage.getItem(KEY));
12      if (x && x.version === 1 && Number.isFinite(x.savedAt) && x.savedAt <= Date.now() && Date.now() - x.savedAt < TTL) return x;
13    } catch (_) { /* Fail closed when storage is blocked or malformed. */ }
14    return null;
15  }
16  function allowed(category) { return !!(current && current[category] === true); }
17  function cleanLocal() {
18    if (!allowed('analytics')) {
19      try { localStorage.removeItem('gex_analytics_visitor_v1'); } catch (_) {}
20      ['gex_analytics_session_v1', 'gex_analytics_seen_v1', 'gex_analytics_touched_v1'].forEach(function (k) { try { sessionStorage.removeItem(k); } catch (_) {} });
21    }
22    if (!allowed('referral')) ['gex_ref_code', 'gex_ref_code_at'].forEach(function (k) { try { localStorage.removeItem(k); } catch (_) {} });
23  }
24  function save(values) {
25    var revoked = current && Object.keys(defaults).some(function (k) { return current[k] === true && values[k] !== true; });
26    current = { version: 1, savedAt: Date.now(), analytics: values.analytics === true, marketing: values.marketing === true, referral: values.referral === true };
27    try { localStorage.setItem(KEY, JSON.stringify(current)); } catch (_) { /* The choice still applies to this page. */ }
28    cleanLocal();
29    close();
30    window.dispatchEvent(new CustomEvent('gex:privacy-changed', { detail: Object.assign({}, current) }));
31    // A loaded third-party pixel cannot be reliably unloaded. Reload with the new denied state.
32    if (revoked) location.reload();
33  }
34  function whenAllowed(category, fn) {
35    var started = false;
36    function run() { if (!started && allowed(category)) { started = true; fn(); } }
37    window.addEventListener('gex:privacy-changed', run);
38    run();
39  }
40  function close() {
41    if (!panel) return;
42    if (panel.open) panel.close();
43    panel.hidden = true;
44    try { sessionStorage.setItem(DISMISSED, '1'); } catch (_) {}
45    if (returnFocus && returnFocus.isConnected) returnFocus.focus();
46  }
47  function open(event) {
48    if (!panel) return;
49    returnFocus = event && event.currentTarget || document.activeElement;
50    Object.keys(defaults).forEach(function (k) { panel.querySelector('[name="' + k + '"]').checked = allowed(k); });
51    panel.hidden = false;
52    if (!panel.open) panel.showModal();
53    panel.querySelector('[data-privacy-reject]').focus();
54  }
55  current = read();
56  cleanLocal();
57  window.GEXPrivacy = Object.freeze({ allowed: allowed, whenAllowed: whenAllowed, open: open });
58  window.dispatchEvent(new CustomEvent('gex:privacy-ready'));
59  window.addEventListener('storage', function (event) {
60    if (event.key !== KEY && event.key !== null) return;
61    var before = current; current = read(); cleanLocal();
62    if (before && Object.keys(defaults).some(function (k) { return before[k] && !allowed(k); })) location.reload();
63    else window.dispatchEvent(new CustomEvent('gex:privacy-changed'));
64  });
65  function mount() {
66    var link = document.createElement('link'); link.rel = 'stylesheet'; link.href = '/assets/privacy-choices.css?v=dialog-20260930'; document.head.appendChild(link);
67    panel = document.createElement('dialog'); panel.className = 'gex-privacy'; panel.hidden = true;
68    panel.setAttribute('aria-labelledby', 'gex-privacy-title'); panel.setAttribute('aria-describedby', 'gex-privacy-summary');
69    panel.innerHTML = '<div class="gex-privacy__head"><span class="gex-privacy__eyebrow">GEX Levels · Privacy</span><button type="button" data-privacy-close aria-label="Close privacy choices">Close</button></div><h2 id="gex-privacy-title">Your privacy, your choice.</h2><p id="gex-privacy-summary">Optional tracking stays off unless you choose it. Refusing or closing this window does not block sign-in or purchases.</p><div class="gex-privacy__essential"><strong>Essential storage · always on</strong><span>Sign-in, security and checkout. Separate from optional tracking and contractual acceptance.</span></div><fieldset><legend>Optional purposes</legend><label><span><strong>Audience measurement</strong><small>First-party page visits to help improve the site.</small></span><input type="checkbox" name="analytics"></label><label><span><strong>Marketing</strong><small>Whop attribution pixel;
69 Meta only if configured.</small></span><input type="checkbox" name="marketing"></label><label><span><strong>Affiliate attribution</strong><small>Remember a referral for up to 30 days.</small></span><input type="checkbox" name="referral"></label></fieldset><div class="gex-privacy__buttons"><button type="button" data-privacy-reject>Reject optional</button><button type="button" data-privacy-accept>Accept all</button><button type="button" data-privacy-save>Save my choices</button></div><p class="gex-privacy__foot">Change your choices anytime using Privacy choices. <a href="/privacy#privacy-storage">Privacy details</a>.</p>';
70    panel.querySelector('[data-privacy-reject]').addEventListener('click', function () { save(defaults); });
71    panel.querySelector('[data-privacy-accept]').addEventListener('click', function () { save({ analytics: true, marketing: true, referral: true }); });
72    panel.querySelector('[data-privacy-close]').addEventListener('click', close);
73    panel.addEventListener('cancel', function (event) { event.preventDefault(); close(); });
74    panel.addEventListener('click', function (event) {
75      if (event.target !== panel) return;
76      var rect = panel.getBoundingClientRect();
77      if (event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom) close();
78    });
79    panel.querySelector('[data-privacy-save]').addEventListener('click', function () { var v = {}; Object.keys(defaults).forEach(function (k) { v[k] = panel.querySelector('[name="' + k + '"]').checked; }); save(v); });
80    document.body.appendChild(panel);
81    trigger = document.createElement('button'); trigger.type = 'button'; trigger.className = 'gex-privacy-trigger'; trigger.textContent = 'Privacy choices'; trigger.setAttribute('aria-haspopup', 'dialog'); trigger.addEventListener('click', open);
82    var footer = document.querySelector('footer'); (footer || document.body).appendChild(trigger);
83    document.querySelectorAll('[data-privacy-open]').forEach(function (button) { button.addEventListener('click', open); });
84    var dismissed = false;
85    try { dismissed = sessionStorage.getItem(DISMISSED) === '1'; } catch (_) {}
86    // Private workspaces stay usable without an intrusive first-visit prompt;
87    // optional tracking still defaults to denied, with choices in settings/footer.
88    if (!current && !dismissed && !document.querySelector('[data-account-page], [data-admin-page]')) open();
89  }
90  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount, { once: true }); else mount();
91})();

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.