PageSourceSearch

https://generationscrewed.ca/wp-content/themes/ctf-generations-screwed/js/gs-join-form.js?ver=1791030605

js generationscrewed.ca collected 2026-10-05 03:46:00 UTC 8,158 bytes, 193 lines download raw bytes

1(function () {
2    'use strict';
3
4    var form = document.getElementById('gs-join-form');
5    if (!form || !form.dataset.gsJoinForm) {
6        return;
7    }
8
9    // form.action is clobbered by the hidden <input name="action">, so read the attribute.
10    var ajaxUrl = form.getAttribute('action');
11    var messages = form.querySelector('.gs-join-form__messages');
12    var submitBtn = form.querySelector('button[type="submit"]');
13    var defaultBtnText = submitBtn ? submitBtn.textContent : '';
14    var cfg = window.ctfGsJoin || {};
15    var submittingText = cfg.submitting || 'Submitting…';
16
17    function showMessage(text, isError) {
18        if (!messages) {
19            return;
20        }
21        messages.hidden = false;
22        messages.textContent = text;
23        messages.classList.toggle('gs-join-form__messages--error', !!isError);
24        messages.classList.toggle('gs-join-form__messages--success', !isError);
25    }
26
27    function clearFieldErrors() {
28        form.querySelectorAll('.gs-join-form__field-error').forEach(function (el) {
29            el.classList.remove('gs-join-form__field-error');
30        });
31        form.querySelectorAll('[data-field-error]').forEach(function (el) {
32            el.removeAttribute('data-field-error');
33        });
34    }
35
36    function markFieldErrors(errors) {
37        if (!errors || typeof errors !== 'object') {
38            return;
39        }
40        Object.keys(errors).forEach(function (name) {
41            var field = form.querySelector('[name="' + name + '"]');
42            if (!field) {
43                return;
44            }
45            var wrap = field.closest('.gs-field, .gs-join-form__fieldset');
46            if (wrap) {
47                wrap.classList.add('gs-join-form__field-error');
48                wrap.setAttribute('data-field-error', errors[name]);
49            }
50        });
51    }
52
53    function bindOtherToggles() {
54        form.querySelectorAll('[data-gs-other-toggle]').forEach(function (radio) {
55            radio.addEventListener('change', function () {
56                var group = radio.name;
57                var otherWrap = form.querySelector('[data-gs-other-for="' + group + '"]');
58                if (!otherWrap) {
59                    return;
60                }
61                var show = form.querySelector('input[name="' + group + '"]:checked');
62                var isOther = show && show.value === 'other';
63                otherWrap.hidden = !isOther;
64                var otherInput = otherWrap.querySelector('input');
65                if (otherInput) {
66                    otherInput.required = isOther;
67                    if (!isOther) {
68                        otherInput.value = '';
69                    }
70                }
71            });
72        });
73    }
74
75    bindOtherToggles();
76
77    form.addEventListener('submit', function (e) {
78        e.preventDefault();
79        if (form.__ctfSubmitInFlight) {
80            return;
81        }
82        clearFieldErrors();
83        if (messages) {
84            messages.hidden = true;
85            messages.textContent = '';
86        }
87
88        if (submitBtn) {
89            submitBtn.disabled = true;
90            submitBtn.textContent = submittingText;
91        }
92
93        form.__ctfSubmitInFlight = true;
94
95        var params = new URLSearchParams(new FormData(form));
96        var recaptcha = window.CTFRecaptchaHandler || {};
97        var submitFn = typeof recaptcha.submitWithToken === 'function'
98            ? recaptcha.submitWithToken.bind(recaptcha)
99            : function(action, fn) {
100                var configured = !(window.ctfRecaptchaStrings && (window.ctfRecaptchaStrings.enabled === false || window.ctfRecaptchaStrings.enabled === '0'));
101                var tokenPromise = typeof recaptcha.getToken === 'function'
102                    ? recaptcha.getToken(action)
103                    : Promise.resolve('');
104                return tokenPromise.then(function(token) {
105                    if (!token && configured) {
106                        var msg = (window.ctfRecaptchaStrings && window.ctfRecaptchaStrings.unavailable)
107                            || 'We couldn\'t run the security check in this browser. Please try again in Safari or Chrome.';
108                        if (typeof recaptcha.reportClientFailure === 'function') {
109                            recaptcha.reportClientFailure(action, { reason: 'script_missing', ua_bucket: 'other' });
110                        }
111                        return {
112                            success: false,
113                            data: { message: msg, recaptcha_unavailable: true }
114                        };
115                    }
116                    if (token) {
117                        params.set('recaptcha_token', token);
118                    }
119                    return fn(token || '', { reason: null });
120                });
121            };
122
123        Promise.resolve().then(function() {
124            return submitFn('gs_join_submit', function(token, meta) {
125                if (token) {
126                    params.set('recaptcha_token', token);
127                } else {
128                    params.delete('recaptcha_token');
129                }
130                if (typeof recaptcha.applyClientReason === 'function') {
131                    recaptcha.applyClientReason(params, meta && meta.reason);
132                }
133                return fetch(ajaxUrl, {
134                    method: 'POST',
135                    credentials: 'same-origin',
136                    headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
137                    body: params.toString(),
138                }).then(function(res) {
139                    return res.json();
140                });
141            });
142        })
143            .then(function (data) {
144                if (data && data.success) {
145                    // Dedicated landing page (/welcome/, /bienvenue/) when
146                    // provisioned; the inline panel below is the fallback.
147                    var successUrl = form.getAttribute('data-success-url');
148                    if (successUrl) {
149                        window.location.assign(successUrl);
150                        return;
151                    }
152                    form.reset();
153                    form.querySelectorAll('[data-gs-other-for]').forEach(function (el) {
154                        el.hidden = true;
155                    });
156                    var successPanel = document.querySelector('[data-gs-join-success]');
157                    if (successPanel) {
158                        form.hidden = true;
159                        successPanel.hidden = false;
160                        successPanel.scrollIntoView({ behavior: 'smooth', block: 'center' });
161                    } else {
162                        var msg = (data.data && data.data.message) || cfg.success || 'Thanks for signing up!';
163                        showMessage(msg, false);
164                        form.scrollIntoView({ behavior: 'smooth', block: 'start' });
165                    }
166                    return;
167                }
168                var errMsg = (data && data.data && data.data.message) || cfg.error || 'Something went wrong. Please try again.';
169                if (data && data.data && data.data.errors) {
170                    markFieldErrors(data.data.errors);
171                    // Surface the first field error (e.g. email typo suggestion) in the banner.
172                    var fieldKeys = Object.keys(data.data.errors);
173                    for (var i = 0; i < fieldKeys.length; i++) {
174                        if (data.data.errors[fieldKeys[i]]) {
175                            errMsg = data.data.errors[fieldKeys[i]];
176                            break;
177                        }
178                    }
179                }
180                showMessage(errMsg, true);
181            })
182            .catch(function () {
183                showMessage(cfg.error || 'Something went wrong. Please try again.', true);
184            })
185            .finally(function () {
186                form.__ctfSubmitInFlight = false;
187                if (submitBtn) {
188                    submitBtn.disabled = false;
189                    submitBtn.textContent = defaultBtnText;
190                }
191            });
192    });
193})();

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.