PageSourceSearch

https://mountaincabinsutah.com/wp-content/plugins/homerunner-conve…/assets/js/core/guest-menu.js?ver=1.159.17

js mountaincabinsutah.com collected 2026-10-10 02:01:26 UTC 15,297 bytes, 433 lines download raw bytes

1/**
2 * CKit Guest Menu
3 *
4 * Dropdown toggle, modal open/close, REST form submit, success state swap,
5 * welcome toast on page load, sign out click handler. Vanilla JS, ES5
6 * compatible to play nicely with older theme JS pipelines.
7 */
8(function () {
9    'use strict';
10
11    var config = window.hrckGuestMenu || {};
12    var strings = config.strings || {};
13
14    function ready(fn) {
15        if (document.readyState !== 'loading') {
16            fn();
17        } else {
18            document.addEventListener('DOMContentLoaded', fn);
19        }
20    }
21
22    ready(function () {
23        initDropdowns();
24        initModal();
25        showWelcomeToastIfFlashed();
26        showErrorToastIfFlagged();
27    });
28
29    // ------------------------------------------------------------------
30    // Dropdowns
31    // ------------------------------------------------------------------
32    function initDropdowns() {
33        var menus = document.querySelectorAll('[data-hrck-guest-menu]');
34        for (var i = 0; i < menus.length; i++) {
35            bindMenu(menus[i]);
36        }
37
38        document.addEventListener('click', function (e) {
39            closeAllMenusExcept(e.target);
40        });
41
42        document.addEventListener('keydown', function (e) {
43            if (e.key === 'Escape') {
44                closeAllMenusExcept(null);
45            }
46        });
47    }
48
49    function bindMenu(menu) {
50        var button = menu.querySelector('.hrck-guest-menu-button');
51        var dropdown = menu.querySelector('.hrck-guest-menu-dropdown');
52        if (!button || !dropdown) { return; }
53
54        button.addEventListener('click', function (e) {
55            e.stopPropagation();
56            var isOpen = dropdown.hasAttribute('hidden') === false;
57            closeAllMenusExcept(menu);
58            if (isOpen) {
59                dropdown.setAttribute('hidden', '');
60                button.setAttribute('aria-expanded', 'false');
61            } else {
62                dropdown.removeAttribute('hidden');
63                button.setAttribute('aria-expanded', 'true');
64            }
65        });
66
67        // Menu item click handlers (modal trigger and REST trigger)
68        dropdown.addEventListener('click', function (e) {
69            var item = e.target.closest('[data-hrck-item]');
70            if (!item) { return; }
71
72            if (item.hasAttribute('data-hrck-modal')) {
73                e.preventDefault();
74                openModal(item.getAttribute('data-hrck-modal'));
75                dropdown.setAttribute('hidden', '');
76                button.setAttribute('aria-expanded', 'false');
77                return;
78            }
79
80            if (item.hasAttribute('data-hrck-rest')) {
81                e.preventDefault();
82                var url = item.getAttribute('data-hrck-rest');
83                restPost(url, {}).then(function () {
84                    window.location.reload();
85                });
86                return;
87            }
88        });
89    }
90
91    function closeAllMenusExcept(insideNode) {
92        var menus = document.querySelectorAll('[data-hrck-guest-menu]');
93        for (var i = 0; i < menus.length; i++) {
94            if (insideNode && menus[i].contains(insideNode)) { continue; }
95            var dd = menus[i].querySelector('.hrck-guest-menu-dropdown');
96            var btn = menus[i].querySelector('.hrck-guest-menu-button');
97            if (dd && !dd.hasAttribute('hidden')) {
98                dd.setAttribute('hidden', '');
99                if (btn) { btn.setAttribute('aria-expanded', 'false'); }
100            }
101        }
102    }
103
104    // ------------------------------------------------------------------
105    // Modal
106    // ------------------------------------------------------------------
107    var resendTimer = null;
108    var lastSubmittedEmail = '';
109
110    function initModal() {
111        var modal = document.getElementById('hrck-signin-modal');
112        if (!modal) { return; }
113
114        // Close triggers
115        modal.addEventListener('click', function (e) {
116            var closer = e.target.closest('[data-hrck-close]');
117            if (closer) {
118                closeModal(modal);
119            }
120        });
121
122        document.addEventListener('keydown', function (e) {
123            if (e.key === 'Escape' && !modal.hasAttribute('hidden')) {
124                closeModal(modal);
125            }
126        });
127
128        // Form submit
129        var form = modal.querySelector('[data-hrck-signin-form]');
130        if (form) {
131            form.addEventListener('submit', function (e) {
132                e.preventDefault();
133                handleFormSubmit(modal, form);
134            });
135        }
136
137        // Resend
138        var resendBtn = modal.querySelector('[data-hrck-resend]');
139        if (resendBtn) {
140            resendBtn.addEventListener('click', function (e) {
141                e.preventDefault();
142                if (resendBtn.disabled) { return; }
143                handleResend(modal);
144            });
145        }
146
147        // Change email
148        var changeBtn = modal.querySelector('[data-hrck-change]');
149        if (changeBtn) {
150            changeBtn.addEventListener('click', function (e) {
151                e.preventDefault();
152                swapState(modal, 'form');
153            });
154        }
155    }
156
157    function openModal(target) {
158        if (target !== 'signin-modal') { return; }
159        var modal = document.getElementById('hrck-signin-modal');
160        if (!modal) { return; }
161        modal.removeAttribute('hidden');
162        var input = modal.querySelector('[name="email"]');
163        if (input) {
164            setTimeout(function () { input.focus(); }, 40);
165        }
166    }
167
168    function closeModal(modal) {
169        modal.setAttribute('hidden', '');
170        swapState(modal, 'form');
171        clearError(modal);
172        if (resendTimer) {
173            clearInterval(resendTimer);
174            resendTimer = null;
175        }
176        // Stream 2: clear pending action state
177        if (window.HRCK) {
178            window.HRCK._pendingAction = null;
179        }
180        var labelEl = document.querySelector('[data-hrck-context-label]');
181        if (labelEl) {
182            labelEl.textContent = '';
183            labelEl.setAttribute('hidden', '');
184        }
185    }
186
187    function swapState(modal, state) {
188        var states = modal.querySelectorAll('[data-hrck-state]');
189        for (var i = 0; i < states.length; i++) {
190            if (states[i].getAttribute('data-hrck-state') === state) {
191                states[i].removeAttribute('hidden');
192            } else {
193                states[i].setAttribute('hidden', '');
194            }
195        }
196    }
197
198    function handleFormSubmit(modal, form) {
199        clearError(modal);
200        var emailInput = form.querySelector('[name="email"]');
201        var consentInput = form.querySelector('[name="consent"]');
202        var submitBtn = form.querySelector('.hrck-guest-modal-submit');
203
204        var email = (emailInput.value || '').trim();
205        if (!isValidEmail(email)) {
206            showError(modal, strings.invalidEmail || 'Please enter a valid email address.');
207            emailInput.focus();
208            return;
209        }
210
211        lastSubmittedEmail = email;
212
213        if (submitBtn) { submitBtn.disabled = true; }
214
215        var postBody = {
216            email: email,
217            consent: consentInput ? !!consentInput.checked : false,
218            origin_url: window.location.href
219        };
220
221        if (window.HRCK && window.HRCK._pendingAction) {
222            postBody.pending_action = window.HRCK._pendingAction;
223            window.HRCK._pendingAction = null;
224        }
225
226        restPost(config.restBase + '/signin', postBody).then(function (res) {
227            if (submitBtn) { submitBtn.disabled = false; }
228            if (res && res.success) {
229                var emailEl = modal.querySelector('[data-hrck-success-email]');
230                if (emailEl) { emailEl.textContent = email; }
231                swapState(modal, 'success');
232                startResendTimer(modal);
233            } else {
234                showError(modal, (res && res.message) || strings.sendFailure || 'Could not send sign in link. Please try again.');
235            }
236        }).catch(function (err) {
237            if (submitBtn) { submitBtn.disabled = false; }
238            if (err && err.status === 429) {
239                showError(modal, strings.rateLimited || 'Too many requests. Please wait a few minutes before trying again.');
240            } else {
241                showError(modal, strings.sendFailure || 'Could not send sign in link. Please try again.');
242            }
243        });
244    }
245
246    function handleResend(modal) {
247        if (!lastSubmittedEmail) { return; }
248        restPost(config.restBase + '/signin', {
249            email: lastSubmittedEmail,
250            consent: true,
251            origin_url: window.location.href
252        }).then(function (res) {
253            if (res && res.success) {
254                startResendTimer(modal);
255            } else {
256                showError(modal, (res && res.message) || strings.sendFailure);
257                swapState(modal, 'form');
258            }
259        });
260    }
261
262    function startResendTimer(modal) {
263        var resendBtn = modal.querySelector('[data-hrck-resend]');
264        if (!resendBtn) { return; }
265
266        var seconds = parseInt(config.resendCooldown, 10) || 30;
267        var baseLabel = (strings.resend || 'Resend link');
268        resendBtn.disabled = true;
269        resendBtn.textContent = baseLabel + ' (' + seconds + 's)';
270
271        if (resendTimer) { clearInterval(resendTimer); }
272        resendTimer = setInterval(function () {
273            seconds--;
274            if (seconds <= 0) {
275                clearInterval(resendTimer);
276                resendTimer = null;
277                resendBtn.disabled = false;
278                resendBtn.textContent = baseLabel;
279            } else {
280                resendBtn.textContent = baseLabel + ' (' + seconds + 's)';
281            }
282        }, 1000);
283    }
284
285    function showError(modal, message) {
286        var errEl = modal.querySelector('[data-hrck-error]');
287        if (!errEl) { return; }
288        errEl.textContent = message;
289        errEl.removeAttribute('hidden');
290    }
291
292    function clearError(modal) {
293        var errEl = modal.querySelector('[data-hrck-error]');
294        if (!errEl) { return; }
295        errEl.textContent = '';
296        errEl.setAttribute('hidden', '');
297    }
298
299    function isValidEmail(value) {
300        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
301    }
302
303    // ------------------------------------------------------------------
304    // REST helper
305    // ------------------------------------------------------------------
306    function restPost(url, body) {
307        return fetch(url, {
308            method: 'POST',
309            credentials: 'same-origin',
310            headers: {
311                'Content-Type': 'application/json',
312                'X-WP-Nonce': config.nonce || ''
313            },
314            body: JSON.stringify(body)
315        }).then(function (response) {
316            if (response.status === 429) {
317                var err = new Error('rate limited');
318                err.status = 429;
319                throw err;
320            }
321            return response.json().catch(function () { return {}; });
322        });
323    }
324
325    // ------------------------------------------------------------------
326    // Welcome toast
327    // ------------------------------------------------------------------
328    function showWelcomeToastIfFlashed() {
329        var flash = config.welcomeFlash;
330        if (!flash) { return; }
331
332        // Stream 2: rich toast from pending action dispatch
333        if (flash.type === 'success' || flash.type === 'error') {
334            var message = flash.message || '';
335            if (flash.detail) {
336                message += ' ' + flash.detail;
337            }
338            if (message) {
339                showToast(message);
340            }
341            cleanupQueryParam('hrck_welcome');
342            return;
343        }
344
345        // Stream 1: simple welcome back toast
346        var flashEmail = flash.email || '';
347        if (!flashEmail && /[\?&]hrck_welcome=1/.test(window.location.search)) {
348            flashEmail = 'you';
349        }
350        if (!flashEmail) { return; }
351
352        showToast((strings.welcomeBack || 'Welcome back, %s').replace('%s', flashEmail));
353        cleanupQueryParam('hrck_welcome');
354    }
355
356    function showErrorToastIfFlagged() {
357        if (/[\?&]hrck_magic_error=1/.test(window.location.search)) {
358            showToast(strings.expiredLink || 'Your sign in link expired. Please request a new one.');
359            cleanupQueryParam('hrck_magic_error');
360        }
361    }
362
363    function showToast(message) {
364        var toast = document.createElement('div');
365        toast.className = 'hrck-guest-toast';
366        toast.textContent = message;
367        toast.setAttribute('role', 'status');
368        document.body.appendChild(toast);
369
370        // Next frame so the transition plays
371        requestAnimationFrame(function () {
372            toast.classList.add('hrck-guest-toast--visible');
373        });
374
375        setTimeout(function () {
376            toast.classList.remove('hrck-guest-toast--visible');
377            setTimeout(function () {
378                if (toast.parentNode) { toast.parentNode.removeChild(toast); }
379            }, 400);
380        }, 4000);
381    }
382
383    function cleanupQueryParam(name) {
384        if (!window.history || !window.history.replaceState) { return; }
385        var url = new URL(window.location.href);
386        url.searchParams.delete(name);
387        window.history.replaceState({}, document.title, url.toString());
388    }
389
390    // ------------------------------------------------------------------
391    // Stream 2: public API for tool handoff to sign-in modal
392    // ------------------------------------------------------------------
393    window.HRCK = window.HRCK || {};
394    window.HRCK.isSignedIn = !!config.isSignedIn;
395
396    /**
397     * Open the sign-in modal with a pending action.
398     *
399     * @param {string} actionName  Filter hook suffix (e.g. 'create_price_alert')
400     * @param {object} params      Tool-specific parameters to carry through
401     * @param {string} contextLabel Optional subtitle shown in the sign-in modal
402     */
403    window.HRCK.openSigninWithAction = function (actionName, params, contextLabel) {
404        window.HRCK._pendingAction = {
405            action: actionName,
406            params: params || {}
407        };
408
409        var labelEl = document.querySelector('[data-hrck-context-label]');
410        if (labelEl) {
411            if (contextLabel) {
412                labelEl.textContent = contextLabel;
413                labelEl.removeAttribute('hidden');
414            } else {
415                labelEl.textContent = '';
416                labelEl.setAttribute('hidden', '');
417            }
418        }
419
420        openModal('signin-modal');
421
422        // v1.37.1: pre-fill the sign-in email input from the handoff params
423        // when the calling tool captured one. Avoids making the user type the
424        // same email in two consecutive modals (Wishlist Share, Price Alerts,
425        // Booking Reminder all flow through this path).
426        if (params && params.email) {
427            var preFillInput = document.querySelector('#hrck-signin-modal [name="email"]');
428            if (preFillInput && !preFillInput.value) {
429                preFillInput.value = params.email;
430            }
431        }
432    };
433})();

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.