1(function() { 2 'use strict'; 3 4 /* How long to wait for ZoomInfo FormComplete before showing the form anyway. 5 This is the intentional wait: FormComplete stamps the form and we would 6 rather show a stamped form than flash an empty one. */ 7 const FALLBACK_TIMEOUT = 3000; 8 9 /* Cosmetic pause between "we have decided to reveal" and actually revealing. 10 This used to be a hard-coded 1000ms that ran on EVERY form, including forms 11 FormComplete had already finished with - a full second of dead time on a 12 perfectly healthy page load. Reveal is now immediate. If a fade is wanted, 13 do it with a CSS transition on .form-ready rather than by delaying here. */ 14 const REVEAL_DELAY = 0; 15 16 const FORM_SELECTORS = [ 17 'form[action="/form-handler"]', 18 'form.form--wrap', 19 'form[name="demoForm"]', 20 'form[data-formtype="demo"]', 21 'form[id*="pardot"]', 22 'form[id*="demo"]' 23 ].join(', '); 24 25 const pendingForms = new Map(); 26 27 /* Set by ZoomInfo's _zi_fc.onReady (registered in wp_head, see 28 includes/theme-scripts.php). May already be true before this footer script 29 parses, which is why it is read rather than only listened for. */ 30 function ziReady() { 31 return window.__assentZiReady === true; 32 } 33 34 /* "Nothing left to wait for" - a page-level flag, not a per-form class. 35 Form visibility used to depend entirely on .loaded sitting on the form 36 itself. Anything that replaces a form in the DOM strips that class, so a 37 VWO campaign swapping a form in re-hid every field; this script put .loaded 38 back; the campaign restored its own copy; repeat. Marking <html> instead 39 means a replaced form is visible immediately without this script touching 40 it, which removes the mutation the campaign was reacting to. 41 Paired with the html:not(.assent-forms-ready) guard in 42 assets/css/form-loading-spinner.css. */ 43 function markGloballyReady() {
44 document.documentElement.classList.add('assent-forms-ready'); 45 } 46 47 function globallyReady() { 48 return document.documentElement.classList.contains('assent-forms-ready'); 49 } 50 51 function isZoomInfoReady(form) { 52 return form.hasAttribute('data-zi-mapped-form') || 53 form.querySelector('input[name*="ZoomInfo"]') || 54 form.querySelector('[data-zi-field]'); 55 } 56 57 /** 58 * Reveal a form. Idempotent. 59 * 60 * Everything that hides the form is undone together, in one pass: 61 * - inline styles written server-side by display_form() in functions.php 62 * - the .form-loading class 63 * - the spinner element 64 * - the .loaded class, which is what form-loading-spinner.css:40 65 * (form:not(.loaded) .form-field { display:none !important }) keys off 66 * 67 * Previously .form-ready was added immediately but everything else waited 68 * 1000ms, so the form sat in a half-revealed state where the spinner was gone 69 * from the logic's point of view but the fields were still display:none. 70 */ 71 function revealForm(form, spinner, observer) { 72 if (form.classList.contains('form-ready')) return; 73 form.classList.add('form-ready'); 74 75 if (observer) observer.disconnect(); 76 pendingForms.delete(form); 77 78 const apply = function() { 79 form.classList.add('loaded'); 80 81 if (!spinner) spinner = form.querySelector('.form-loading-spinner'); 82 if (spinner && spinner.parentNode) spinner.remove(); 83 84 form.classList.remove('form-loading'); 85 form.style.removeProperty('visibility'); 86 form.style.removeProperty('pointer-events'); 87 form.style.removeProperty('position'); 88 form.style.removeProperty('min-height'); 89 form.style.removeProperty('max-height'); 90 form.style.removeProperty('margin-top'); 91 form.style.removeProperty('margin-bottom'); 92 93 /* Measure after the browser has applied the removals above, otherwise 94 offsetHeight can be read against the old max-height:72px box. */ 95 if (typeof globalGapMaker === 'function') { 96 requestAnimationFrame(function() { 97 const consentStmt = form.querySelector('.consent-stmt'); 98 if (consentStmt) { 99 form.style.marginBottom = (30 + consentStmt.offsetHeight) + 'px'; 100 } 101 }); 102 } 103 }; 104 105 if (REVEAL_DELAY > 0) setTimeout(apply, REVEAL_DELAY); 106 else apply(); 107 } 108 109 /* Reveal every form on the page. Called by ZoomInfo's onReady callback. */ 110 function revealAll() { 111 markGloballyReady(); 112 113 pendingForms.forEach(function(entry, form) { 114 revealForm(form, entry.spinner, entry.observer); 115 });
116 document.querySelectorAll(FORM_SELECTORS).forEach(function(form) { 117 revealForm(form, form.querySelector('.form-loading-spinner'), null); 118 }); 119 } 120 121 function initFormLoader(form) { 122 if (form.dataset.loaderInitialized) return; 123 form.dataset.loaderInitialized = 'true'; 124 125 /* Already stamped, or FormComplete has finished everywhere: show it now. 126 The old code returned early when ZoomInfo was done WITHOUT revealing, 127 which left any form added after that point hidden by its inline styles 128 with no timer left to clear them. */ 129 if (ziReady() || isZoomInfoReady(form)) { 130 revealForm(form, form.querySelector('.form-loading-spinner'), null); 131 return; 132 } 133 134 let spinner = form.querySelector('.form-loading-spinner'); 135 136 if (!spinner) { 137 form.style.visibility = 'hidden'; 138 form.style.pointerEvents = 'none'; 139 form.style.position = 'relative'; 140 form.style.minHeight = '72px'; 141 form.style.maxHeight = '72px'; 142 form.style.setProperty('margin-top', '24px', 'important'); 143 form.style.marginBottom = '62px'; 144 form.classList.add('form-loading'); 145 spinner = document.createElement('div'); 146 spinner.className = 'form-loading-spinner'; 147 form.insertBefore(spinner, form.firstChild); 148 } 149 150 const observer = new MutationObserver(function() { 151 if (isZoomInfoReady(form)) revealForm(form, spinner, observer); 152 }); 153 observer.observe(form, { childList: true, subtree: true, attributes: true }); 154 155 pendingForms.set(form, { spinner: spinner, observer: observer }); 156 157 setTimeout(function() { 158 revealForm(form, spinner, observer); 159 }, FALLBACK_TIMEOUT); 160 } 161 162 function initAllForms() {
163 document.querySelectorAll(FORM_SELECTORS).forEach(initFormLoader); 164 } 165 166 /* Only needed while we are still waiting for FormComplete: a form that shows 167 up after that needs no spinner, no timer and no observer, because the CSS 168 no longer hides it. Bailing out here is what stops this script and a VWO 169 campaign taking turns rewriting the same form. */ 170 function watchForNewForms() { 171 new MutationObserver(function(mutations) { 172 if (globallyReady()) return; 173 174 mutations.forEach(function(mutation) { 175 mutation.addedNodes.forEach(function(node) { 176 if (node.nodeType !== Node.ELEMENT_NODE) return; 177 if (node.matches && node.matches(FORM_SELECTORS)) initFormLoader(node); 178 if (node.querySelectorAll) node.querySelectorAll(FORM_SELECTORS).forEach(initFormLoader); 179 }); 180 }); 181 }).observe(document.body, { childList: true, subtree: true }); 182 } 183 184 /* Catch forms FormComplete stamped without a mutation the observer saw 185 (replaces the old checkIfZoomInfoAlreadyRan). */ 186 function sweepStamped() {
187 document.querySelectorAll(FORM_SELECTORS).forEach(function(form) { 188 if (!isZoomInfoReady(form)) return; 189 const entry = pendingForms.get(form); 190 revealForm(form, entry ? entry.spinner : null, entry ? entry.observer : null); 191 }); 192 } 193 194 function start() { 195 initAllForms(); 196 watchForNewForms(); 197 if (ziReady()) revealAll(); 198 else sweepStamped(); 199 } 200 201 /* initialization */ 202 if (document.readyState === 'loading') { 203 document.addEventListener('DOMContentLoaded', start); 204 } else { 205 start(); 206 } 207 208 /* Backstop: if FormComplete never reports ready, stop hiding fields anyway 209 after the same wait a single form would have used. Without this a page 210 where ZoomInfo fails outright would keep the CSS rule live indefinitely. */ 211 setTimeout(markGloballyReady, FALLBACK_TIMEOUT); 212 213 window.addEventListener('load', function() { 214 initAllForms(); 215 if (ziReady()) revealAll(); 216 else sweepStamped(); 217 }); 218 219 window.AssentFormLoader = { 220 init: initAllForms, 221 initForm: initFormLoader, 222 revealAll: revealAll 223 }; 224})();
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.