PageSourceSearch

https://brusselssignal.eu/content/themes/brusselssignal.eu/assets/…/partner-contact-modal.js?ver=1790423896

js brusselssignal.eu collected 2026-10-02 03:00:04 UTC 5,954 bytes, 176 lines download raw bytes

1(function () {
2    const config = window.bsPartnerContact || {};
3    const forms = document.querySelectorAll('[data-partner-contact-form]');
4
5    if (!forms.length || !config.endpoint || !config.nonce) {
6        return;
7    }
8
9    // Wires one form instance up independently (its own challenge state,
10    // status element, submit handler) — there can be more than one on a
11    // page at once, e.g. the site-wide "Contact Us" modal (in every page's
12    // header.php) plus an inline copy of the same form embedded directly
13    // on a page like About. Returns ensureChallenge so a caller elsewhere
14    // (the modal-open trigger below) can pre-fetch for a *specific*
15    // instance rather than guessing which form on the page it means.
16    function setupForm(form) {
17        const status = form.querySelector('[data-partner-contact-status]');
18        const submitButton = form.querySelector('button[type="submit"]');
19        const startedAtField = form.querySelector('input[name="started_at"]');
20        const challengeIdField = form.querySelector('input[name="challenge_id"]');
21        const challengeTokenField = form.querySelector('input[name="challenge_token"]');
22        let challengePromise = null;
23
24        function setStatus(message, type) {
25            if (!status) {
26                return;
27            }
28
29            status.textContent = message || '';
30            status.classList.remove('is-error', 'is-success');
31
32            if (type) {
33                status.classList.add(`is-${type}`);
34            }
35        }
36
37        function setBusy(isBusy) {
38            if (!submitButton) {
39                return;
40            }
41
42            submitButton.disabled = isBusy;
43            submitButton.setAttribute('aria-busy', isBusy ? 'true' : 'false');
44        }
45
46        function clearChallenge() {
47            challengePromise = null;
48
49            if (challengeIdField) {
50                challengeIdField.value = '';
51            }
52
53            if (challengeTokenField) {
54                challengeTokenField.value = '';
55            }
56        }
57
58        async function requestChallenge() {
59            if (!config.challengeEndpoint || !challengeIdField || !challengeTokenField) {
60                throw new Error(config.errorMessage);
61            }
62
63            const response = await fetch(config.challengeEndpoint, {
64                method: 'POST',
65                headers: {
66                    'Content-Type': 'application/json',
67                    'X-WP-Nonce': config.nonce,
68                },
69                credentials: 'same-origin',
70                body: JSON.stringify({}),
71            });
72
73            const data = await response.json().catch(() => ({}));
74            if (!response.ok || !data.challengeId || !data.challengeToken) {
75                throw new Error(data.message || config.errorMessage);
76            }
77
78            challengeIdField.value = data.challengeId;
79            challengeTokenField.value = data.challengeToken;
80
81            if (startedAtField) {
82                startedAtField.value = String(Math.floor(Date.now() / 1000));
83            }
84
85            return data;
86        }
87
88        function ensureChallenge() {
89            if (challengeIdField?.value && challengeTokenField?.value) {
90                return Promise.resolve();
91            }
92
93            if (!challengePromise) {
94                challengePromise = requestChallenge().catch((error) => {
95                    clearChallenge();
96                    throw error;
97                });
98            }
99
100            return challengePromise;
101        }
102
103        form.addEventListener('focusin', () => {
104            ensureChallenge().catch(() => {});
105        });
106
107        form.addEventListener('submit', async (event) => {
108            event.preventDefault();
109
110            if (!form.checkValidity()) {
111                form.reportValidity();
112                return;
113            }
114
115            setBusy(true);
116            setStatus('', '');
117
118            try {
119                await ensureChallenge();
120
121                const payload = Object.fromEntries(new FormData(form).entries());
122                payload.page_url = window.location.href;
123
124                const response = await fetch(config.endpoint, {
125                    method: 'POST',
126                    headers: {
127                        'Content-Type': 'application/json',
128                        'X-WP-Nonce': config.nonce,
129                    },
130                    credentials: 'same-origin',
131                    body: JSON.stringify(payload),
132                });
133
134                const data = await response.json().catch(() => ({}));
135
136                if (!response.ok) {
137                    throw new Error(data.message || config.errorMessage);
138                }
139
140                form.reset();
141                clearChallenge();
142                setStatus(data.message || config.successMessage, 'success');
143            } catch (error) {
144                clearChallenge();
145                setStatus(error instanceof Error ? error.message : config.errorMessage, 'error');
146            } finally {
147                setBusy(false);
148            }
149        });
150
151        return { ensureChallenge };
152    }
153
154    let modalFormEnsureChallenge = null;
155
156    forms.forEach((form) => {
157        const instance = setupForm(form);
158
159        if (form.closest(`#${config.modalId}`)) {
160            modalFormEnsureChallenge = instance.ensureChallenge;
161        }
162    });
163
164    // Pre-fetches a challenge as soon as the modal is opened, specifically
165    // for the modal's own form instance — an inline form elsewhere on the
166    // page (e.g. About) pre-fetches for itself independently, via its own
167    // focusin listener set up above.
168    document.addEventListener('click', (event) => {
169        const trigger = event.target.closest(`[data-modal-open="${config.modalId}"]`);
170        if (!trigger || !modalFormEnsureChallenge) {
171            return;
172        }
173
174        modalFormEnsureChallenge().catch(() => {});
175    });
176})();

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.