1/** 2 * CCPA "Do Not Sell My Personal Information" opt-out form handler. 3 * 4 * Uses event delegation on the document so it works even when the shortcode 5 * HTML is injected into the DOM client-side by page builders (Bricks, etc.). 6 * Localized config is provided via fazDnsmpiConfig (wp_localize_script). 7 */ 8(function () { 9 'use strict'; 10 11 function getConfig() { 12 return window.fazDnsmpiConfig || {}; 13 } 14 15 function normalizeMessage(payload, fallback) { 16 if (payload && typeof payload === 'object' && payload.message) { 17 return String(payload.message); 18 } 19 if (typeof payload === 'string' && payload) { 20 return payload; 21 } 22 if (payload && typeof payload === 'object') { 23 try { 24 return JSON.stringify(payload); 25 } catch (e) {} 26 } 27 return fallback || 'An error occurred. Please try again.'; 28 } 29 30 function handleSubmit(e) { 31 var form = e.target; 32 if (!form) return; 33 var isOptout = form.classList && form.classList.contains('faz-dnsmpi-form'); 34 var isRescind = form.classList && form.classList.contains('faz-dnsmpi-rescind-form'); 35 if (!isOptout && !isRescind) return; 36 37 // Per-form sentinel guards against double-fire: if the script is 38 // enqueued twice (e.g. an AJAX-loaded widget brings a second copy of 39 // the asset) the document-level submit listener also fires twice for 40 // the same submit, and the second fetch() trips the per-IP add_option 41 // lock â the user sees "Too many requests" after having successfully 42 // opted out on the first request. Mirrors faz-dsar.js:_fazDsarAttached. 43 if (form._fazDnsmpiAttached) { 44 e.preventDefault(); 45 return; 46 } 47 form._fazDnsmpiAttached = true; 48 e.preventDefault(); 49 50 var wrap = form.parentElement; 51 if (!wrap) return; 52 var notice = wrap.querySelector('.faz-dnsmpi-notice:not(.success)') || wrap.querySelector('.faz-dnsmpi-notice'); 53 var btn = form.querySelector('button'); 54 if (btn) btn.disabled = true; 55 if (btn) btn.setAttribute('aria-busy', 'true'); 56 57 // On every error path below we'll release the sentinel so the user 58 // can retry after fixing whatever was wrong (network drop, server 59 // error, validation rejection). Success path leaves it true â the 60 // form is hidden anyway and any subsequent submit would be on stale 61 // state. 62 function releaseSentinel() { form._fazDnsmpiAttached = false; } 63 64 var config = getConfig(); 65 if (!config.ajaxUrl) { 66 if (btn) btn.disabled = false; 67 if (btn) btn.setAttribute('aria-busy', 'false'); 68 if (notice) { 69 // Switch the live-region to role=alert so screen readers 70 // announce the error assertively (the static markup ships with 71 // role=status / aria-live=polite, which queues behind the 72 // current utterance and may be missed entirely on a submit 73 // that errored out immediately). Mirrors setNoticeError() in 74 // faz-dsar.js. 75 notice.setAttribute('role', 'alert'); 76 notice.setAttribute('aria-live', 'assertive'); 77 notice.className = 'faz-dnsmpi-notice error'; 78 notice.textContent = normalizeMessage('', config.errMsg); 79 notice.style.display = 'block'; 80 } 81 releaseSentinel(); 82 return; 83 } 84 85 var data = new FormData(form); 86 var successFallback = isRescind 87 ? (config.rescindSuccess || 'Your opt-out has been withdrawn.') 88 : (config.successMsg || 'Request submitted successfully.'); 89 90 fetch(config.ajaxUrl, { 91 method: 'POST', 92 credentials: 'same-origin', 93 body: data, 94 }) 95 .then(function (r) { return r.json(); }) 96 .then(function (res) { 97 if (notice) { 98 notice.style.display = 'block'; 99 if (res.success) { 100 // Success: reset to role=status (polite) so the 101 // confirmation doesn't bark in user's ears. 102 notice.setAttribute('role', 'status'); 103 notice.setAttribute('aria-live', 'polite'); 104 notice.className = 'faz-dnsmpi-notice success'; 105 notice.textContent = normalizeMessage(res.data, successFallback); 106 form.style.display = 'none'; 107 notice.tabIndex = -1; 108 notice.focus(); 109 // Rescind succeeded â reload so the page re-renders the opt-out 110 // form (server-side state changed: cookie cleared). Delay so 111 // screen readers can announce the success notice first. 112 // Reload after either action so the server-side state change 113 // applies immediately on this page, not just on the next navigation: 114 // a rescind clears the opt-out cookie; an opt-out sets it, and 115 // get_blocked_categories() then blocks the sell/share scripts on the 116 // reloaded response. 117 setTimeout(function () { window.location.reload(); }, 800); 118 } else { 119 // Failure: assertive announcement. 120 notice.setAttribute('role', 'alert'); 121 notice.setAttribute('aria-live', 'assertive'); 122 notice.className = 'faz-dnsmpi-notice error'; 123 notice.textContent = normalizeMessage(res.data, config.errMsg); 124 form.style.display = 'block'; 125 if (btn) btn.disabled = false;
126 if (btn) btn.setAttribute('aria-busy', 'false'); 127 releaseSentinel(); 128 } 129 } 130 }) 131 .catch(function () { 132 if (btn) btn.disabled = false; 133 if (btn) btn.setAttribute('aria-busy', 'false'); 134 form.style.display = 'block'; 135 if (notice) { 136 notice.setAttribute('role', 'alert'); 137 notice.setAttribute('aria-live', 'assertive'); 138 notice.className = 'faz-dnsmpi-notice error'; 139 notice.textContent = normalizeMessage('', getConfig().netMsg); 140 notice.style.display = 'block'; 141 } 142 releaseSentinel(); 143 }); 144 } 145 146 if (document.readyState === 'loading') { 147 document.addEventListener('DOMContentLoaded', function () { 148 document.addEventListener('submit', handleSubmit); 149 }); 150 } else { 151 document.addEventListener('submit', handleSubmit); 152 } 153})();
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.