PageSourceSearch

https://www.georgiaaquarium.org/wp-content/themes/georgia-aquarium…dent-promo-visibility.js?ver=20261001185942

js georgiaaquarium.org collected 2026-10-02 09:50:40 UTC 6,238 bytes, 132 lines download raw bytes

1/**
2 * Georgia Residents promo card visibility / link rewriter.
3 *
4 * Two locations carry a "Login to Verify" CTA tied to the Georgia Residents
5 * Summer 2026 promo: the home page's Immersive Hero promo slider, and a card
6 * on the Special Offers page. This script reads the JS-readable resident
7 * cookie (STYXKEY_GAQ_GARES, set by the Tessitura-GAI plugin — see
8 * TessAPI::setGAResidentCookie() and the three triggers in TessAPI.php +
9 * RestAPI.php + session.js) and adjusts those cards accordingly:
10 *
11 *   - Cookie absent (guest / pre-cookie session) → leave UI untouched.
12 *   - Cookie === '1' (logged-in GA resident)     → rewrite the CTA href to
13 *                                                  /tickets and change the
14 *                                                  visible text to "Buy Tickets".
15 *   - Cookie === '0' (logged-in non-resident)    → remove the entire slide /
16 *                                                  card from the DOM. If the
17 *                                                  removal leaves the immersive
18 *                                                  hero promo slider with 0
19 *                                                  slides, remove the whole
20 *                                                  drawer; with 1 slide, hide
21 *                                                  the prev/next controls.
22 *
23 * Detection is text-based: any <a> whose normalized text is "login to verify"
24 * AND whose nearest ancestor matches the page-scoped block selector set is
25 * treated as a resident promo CTA. The containment gate is what prevents an
26 * unrelated "Login to Verify" link elsewhere on a page from being hijacked.
27 *
28 * This script is enqueued as a standalone footer file with no $(document).ready
29 * wrapper, so the IIFE runs synchronously at parse time after the DOM is
30 * parsed but before new_home_scripts.js (which initializes the immersive hero
31 * slider) executes. functions.php enforces that load order by adding this
32 * script to new_home_scripts' dependency array.
33 */
34(function() {
35    'use strict';
36
37    var match = document.cookie.match(/(?:^|;\s*)STYXKEY_GAQ_GARES=(\d)/);
38    var residentState = match ? match[1] : null;
39    if (residentState === null) { return; } // guest / pre-cookie — bail out
40
41    // Page-scoped block selectors. The home-page slide selector is global
42    // (only present on pages that render the Immersive Hero). The Special
43    // Offers card selector is intentionally scoped to /special-offers so a
44    // future page that happens to reuse .options-grid__element doesn't pick
45    // up resident-promo behavior unintentionally.
46    var path = window.location.pathname.replace(/\/+$/, '');
47    var blockSelectors = ['.immersive-hero__promo-slide'];
48    if (path === '/special-offers') {
49        blockSelectors.push('.options-grid__element');
50    }
51    var BLOCK_SELECTORS = blockSelectors.join(',');
52
53    function findResidentCTAs() {
54        var ctas = [];
55        var anchors = document.querySelectorAll('a');
56        for (var i = 0; i < anchors.length; i++) {
57            var a = anchors[i];
58            if ((a.textContent || '').trim().toLowerCase() === 'login to verify') {
59                ctas.push(a);
60            }
61        }
62        return ctas;
63    }
64
65    // Returns true if cta should be handled even outside a BLOCK_SELECTORS
66    // container — currently: any <a class="button"> with the resident-promo text.
67    function isStandaloneResidentCTA(cta) {
68        return cta.classList.contains('button');
69    }
70
71    function rewriteCtaText(cta, newText) {
72        // Most CTAs in this codebase wrap their visible label in a
73        // <span class="button__text">. Prefer that when present so the
74        // adjacent .link__arrow / svg children are preserved untouched.
75        var btnText = cta.querySelector('.button__text');
76        if (btnText) {
77            btnText.textContent = newText;
78            return;
79        }
80        // Fallback: replace the first non-empty text node in the link's
81        // direct children. This preserves element children like inline SVGs.
82        for (var i = 0; i < cta.childNodes.length; i++) {
83            var n = cta.childNodes[i];
84            if (n.nodeType === 3 /* TEXT_NODE */ && n.nodeValue.trim()) {
85                n.nodeValue = newText;
86                return;
87            }
88        }
89        // Last resort — nothing matched. Overwrite the link content entirely.
90        cta.textContent = newText;
91    }
92
93    var removalsHappened = false;
94
95    findResidentCTAs().forEach(function(cta) {
96        var card = cta.closest(BLOCK_SELECTORS);
97        if (!card && !isStandaloneResidentCTA(cta)) { return; }
98
99        if (residentState === '1') {
100            cta.href = '/tickets';
101            rewriteCtaText(cta, 'Buy Tickets');
102        } else if (residentState === '0') {
103            // For standalone button CTAs with no containing card, remove the
104            // button itself rather than a parent block.
105            var target = card || cta;
106            target.parentNode && target.parentNode.removeChild(target);
107            removalsHappened = true;
108        }
109    });
110
111    // Immersive Hero promo drawer cleanup. Mirrors the masthead pattern in
112    // assets/js/new-home/masthead.js (~lines 27-39): after the targeted
113    // children are removed, recount and either kill the whole drawer (0
114    // slides) or just hide the prev/next nav (1 slide). Only runs when we
115    // actually removed something, so the resident-state-'1' path and the
116    // no-op guest path don't touch the drawer.
117    if (removalsHappened) {
118        var drawers = document.querySelectorAll('.immersive-hero__promo');
119        for (var d = 0; d < drawers.length; d++) {
120            var drawer = drawers[d];
121            var remaining = drawer.querySelectorAll('.immersive-hero__promo-slide').length;
122            if (remaining === 0) {
123                drawer.parentNode && drawer.parentNode.removeChild(drawer);
124            } else if (remaining === 1) {
125                var bottom = drawer.querySelector('.immersive-hero__promo-bottom');
126                if (bottom) {
127                    bottom.classList.add('immersive-hero__promo-bottom--hidden');
128                }
129            }
130        }
131    }
132})();

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.