PageSourceSearch

https://www.chuckecheese.com/wp-content/themes/chuckecheese-theme/dist/js/location-handler.js

js chuckecheese.com collected 2026-10-01 10:45:16 UTC 10,483 bytes, 280 lines download raw bytes

1(function () {
2    let validSlugs = null; 
3    const CACHE_KEY = 'cec_valid_slugs_data';
4    const CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24 hours
5
6    /**
7     * 1. Hardened Fetching with Defensive Filtering
8     */
9    async function fetchValidSlugs() {
10        if (validSlugs !== null) return validSlugs;
11
12        try {
13            const cached = localStorage.getItem(CACHE_KEY);
14            if (cached) {
15                const { slugs, timestamp } = JSON.parse(cached);
16                if (Date.now() - timestamp < CACHE_EXPIRY && Array.isArray(slugs)) {
17                    validSlugs = slugs;
18                    return validSlugs;
19                }
20            }
21        } catch (_) {}
22
23        try {
24            const response = await fetch('/wp-content/uploads/location-slugs.json', { cache: "no-cache" });
25            if (!response.ok) throw new Error("Network error");
26            const data = await response.json();
27
28            if (Array.isArray(data.valid_slugs)) {
29                // Filter out bad data and normalize to lowercase
30                validSlugs = data.valid_slugs
31                    .filter(s => s && typeof s.slug === "string")
32                    .map(s => ({ ...s, slug: s.slug.toLowerCase() }));
33                
34                try { 
35                    localStorage.setItem(CACHE_KEY, JSON.stringify({ slugs: validSlugs, timestamp: Date.now() })); 
36                } catch (_) {}
37                return validSlugs;
38            }
39        } catch (error) {
40            console.error("Location fetch failed:", error);
41        }
42        return [];
43    }
44
45    function getCookie(name) {
46        const matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([.*+?^${}()|[\]\\])/g, '\\$1') + "=([^;]*)"));
47        return matches ? decodeURIComponent(matches[1]) : undefined;
48    }
49
50    function setCookie(name, value, days) {
51        let expires = "";
52        if (days >= 0) {
53            let date = new Date();
54            date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
55            expires = "; expires=" + date.toUTCString();
56        } else {
57            expires = "; expires=Thu, 01 Jan 1970 00:00:00 GMT";
58        }
59        const host = window.location.hostname;
60        const isLocal =
61            host === "localhost" ||
62            host === "127.0.0.1" ||
63            host.endsWith(".local") ||
64            host.endsWith(".test");
65        const isChuck = host.endsWith("chuckecheese.com");
66        const isHttps = window.location.protocol === "https:";
67        const domainAttr = isChuck ? "; domain=.chuckecheese.com" : "";
68        const secureAttr = !isLocal && isHttps ? "; Secure" : "";
69        document.cookie = `${name}=${encodeURIComponent(value)}${expires}; path=/${domainAttr}; SameSite=Lax${secureAttr}`;
70    }
71
72    function lockLocationPickerFlag(value) {
73        try {
74            Object.defineProperty(window, "CEC_SHOW_LOCATION_PICKER", {
75                value: !!value,
76                writable: false,
77                configurable: false,
78                enumerable: true,
79            });
80        } catch (_) {
81            window.CEC_SHOW_LOCATION_PICKER = !!value;
82        }
83    }
84
85    function normalizePath(path) {
86        if (!path || path === "") return "/";
87        return path.startsWith("/") ? path : `/${path}`;
88    }
89
90    function isUtilityPath(pathname) {
91        return ["/select-location/", "/select-location"].includes(pathname);
92    }
93
94    function stripSlugFromPath(pathname, validSlugsList) {
95        const normalizedPath = normalizePath(pathname);
96        const segments = normalizedPath.split("/").filter(Boolean);
97
98        if (segments.length === 0) return "/";
99
100        const firstSegment = (segments[0] || "").toLowerCase();
101        const isSlugged = validSlugsList.some(s => s.slug === firstSegment);
102
103        if (!isSlugged) return normalizedPath;
104
105        const stripped = `/${segments.slice(1).join("/")}`;
106        return stripped === "/" || stripped === "" ? "/" : stripped;
107    }
108
109    async function getCurrentReturnPath() {
110        const slugs = await fetchValidSlugs();
111        const { pathname, search, hash } = window.location;
112
113        // If slugs failed to load, don't try to strip — return bare path
114        if (!slugs || slugs.length === 0) {
115            const cleanPath = isUtilityPath(pathname) ? "/" : pathname;
116            return `${cleanPath}${search}${hash}`;
117        }
118
119        let cleanPath = pathname;
120
121        if (!isUtilityPath(pathname)) {
122            cleanPath = stripSlugFromPath(pathname, slugs);
123        } else {
124            cleanPath = "/";
125        }
126
127        return `${cleanPath}${search}${hash}`;
128    }
129
130    function is404Page() {
131        return window.CEC_IS_404 === true;
132    }
133
134    function shouldAutoOpenLocationPicker(pathname) {
135        const utilityPaths = ["/", "/select-location/", "/select-location"];
136        if (is404Page()) return false;
137        return !utilityPaths.includes(pathname);
138    }
139
140
141    /**
142     * Helper: Clean localization for a single anchor
143     */
144    function localizeLink(link, userSlug, validSlugsList, origin) {
145        const href = link.getAttribute("href");
146        if (!href
147            || href.startsWith("#")
148            || href.startsWith("mailto:")
149            || href.startsWith("tel:")
150            || href.includes("wp-admin")
151            || href.includes("wp-content")
152        ) return;
153
154        let url;
155        try { url = new URL(href, origin); } catch { return; }
156
157        if (url.origin !== origin) return;
158
159        const pathSegments = url.pathname.split("/").filter(Boolean);
160        const firstSegment = (pathSegments[0] || "").toLowerCase();
161
162        if (firstSegment === userSlug) return; 
163
164        const isSlugged = validSlugsList.some(s => s.slug === firstSegment);
165        const utilityPaths = ["/", "/select-location/", "/select-location"];
166        const isUtility = utilityPaths.includes(url.pathname);
167
168        if (!isSlugged && !isUtility) {
169            url.pathname = `/${userSlug}${url.pathname}`;
170            link.href = url.toString();
171        }
172    }
173
174    /**
175     * 2. Hardened Redirection with Cookie Normalization
176     */
177    async function handleRedirection() {
178        const slugs = await fetchValidSlugs();
179        if (!Array.isArray(slugs) || slugs.length === 0) return;
180
181        const cookie = getCookie("cecLocation");
182        const { pathname, search, hash, origin } = window.location;
183        const isAsset = pathname.startsWith("/wp-content/")
184            || /\.(css|js|map|json|xml|txt|png|jpg|jpeg|gif|svg|webp|ico|pdf)$/i.test(pathname);
185        if (isAsset) return;
186        const firstSegment = (pathname.split("/").filter(Boolean)[0] || "").toLowerCase();
187        const isSlugged = slugs.some(s => s.slug === firstSegment);
188
189        // SYNC: URL overrides Cookie
190        if (isSlugged) {
191            const urlMatch = slugs.find(s => s.slug === firstSegment);
192            if (urlMatch) {
193                setCookie('cecLocation', JSON.stringify(urlMatch), 365);
194                lockLocationPickerFlag(false);
195            }
196            return;
197        }
198
199        if (cookie) {
200            try {
201                const locationData = JSON.parse(cookie);
202                
203                // NORMALIZE: Ensure cookie slug is lowercase for validation
204                const cookieSlug = (locationData.slug || "").toLowerCase();
205                const cookieSlugValid = slugs.some(s => s.slug === cookieSlug);
206
207                if (!cookieSlugValid) {
208                    setCookie('cecLocation', '', -1);
209                    if (shouldAutoOpenLocationPicker(pathname)) {
210                        setLocationPickerFlag(true);
211                    }
212                    return;
213                }
214
215                // Valid cookie should suppress the picker redirect
216                lockLocationPickerFlag(false);
217
218                // Global utility paths should not be slug-forced
219                const utilityPaths = ["/select-location/", "/select-location"];
220                if (utilityPaths.includes(pathname)) return;
221
222                if (pathname === "/") {
223                    window.location.replace(`${origin}/${cookieSlug}${search}${hash}`);
224                    return;
225                }
226
227                window.location.replace(`${origin}/${cookieSlug}${pathname}${search}${hash}`);
228            } catch (e) { console.error("Cookie sync error", e); }
229        } else {
230            if (shouldAutoOpenLocationPicker(pathname)) {
231                setLocationPickerFlag(true);
232            }
233        }
234    }
235
236    async function updateLocalLinks() {
237        const slugs = await fetchValidSlugs();
238        const cookie = getCookie("cecLocation");
239        if (!cookie) return;
240
241        try {
242            // NORMALIZE: User slug for link localization
243            const { slug } = JSON.parse(cookie);
244            const userSlug = (slug || "").toLowerCase();
245            const origin = window.location.origin;
246
247            document.querySelectorAll("a[href]").forEach(link => {
248                localizeLink(link, userSlug, slugs, origin);
249            });
250
251            const observer = new MutationObserver((mutations) => {
252                mutations.forEach((m) => {
253                    m.addedNodes.forEach((node) => {
254                        if (node.nodeType !== 1) return;
255                        if (node.tagName === 'A') localizeLink(node, userSlug, slugs, origin);
256                        node.querySelectorAll("a[href]").forEach(l => localizeLink(l, userSlug, slugs, origin));
257                    });
258                });
259            });
260            observer.observe(document.body, { childList: true, subtree: true });
261        } catch (e) { console.error("Link update failed:", e); }
262    }
263
264    async function init() {
265        if (window.location.search === "?undefined") {
266            window.history.replaceState({}, "", window.location.pathname + window.location.hash);
267        }
268
269        await handleRedirection();
270        
271        if (document.readyState === "loading") {
272            document.addEventListener("DOMContentLoaded", updateLocalLinks);
273        } else {
274            updateLocalLinks();
275        }
276    }
277
278    window.CEC_getCurrentReturnPath = getCurrentReturnPath;
279    init();
280})();

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.