1/* 2 Head-only: checkbox-triggered create with re-open support. 3 - Listens for field [data-field-name="I was referred"] change event. 4 - Idempotent: prevents duplicates but allows re-create when user closes and checks again. 5*/ 6(function(){ 7 8 function log(){ console.log.apply(console, [LOG_PREFIX].concat(Array.from(arguments))); } 9 function warn(){ console.warn.apply(console, [LOG_PREFIX].concat(Array.from(arguments))); } 10 function err(){ console.error.apply(console, [LOG_PREFIX].concat(Array.from(arguments))); } 11 12 // ==== VERSION MARKER (for debugging) ==== 13 var HEAD_CHECKBOX_VERSION = "HeadCheckbox v2.1 â Yes/No support"; 14 try { 15 log("Loaded script version:", HEAD_CHECKBOX_VERSION, "CHECK_SELECTOR =", (typeof CHECK_SELECTOR !== "undefined" ? CHECK_SELECTOR : "(undefined)")); 16 } catch(e) { 17 // if LOG_PREFIX or CHECK_SELECTOR blow up for some reason, fail silently 18 console.log("[HeadCheckbox] (fallback) Loaded script version:", HEAD_CHECKBOX_VERSION); 19 } 20 // ======================================== 21 22 // Field-only guard (URL no longer required) 23 try { 24 if (!CHECK_SELECTOR) { 25 log("Field guard: no field name provided, skipping injection."); 26 return; 27 } 28 log("Field guard passed â monitoring field:", CHECK_SELECTOR); 29 } catch(e){ 30 warn("Field guard check failed â skipping.", e); 31 return; 32 } 33 34 // global state for idempotency and lock 35 window.__HeadCreated = window.__HeadCreated || {}; 36 window.__HeadCreating = window.__HeadCreating || {}; 37 38 // spinner markup 39 var SPINNER_HTML = '<div id="' + SPINNER_ID + '" style="background-color:rgba(0,0,0,0.5); position:fixed; width:100vw; height:100vh; top:0; left:0; z-index:999998; display:flex; align-items:center; justify-content:center;">' 40 + '<div class="slds-spinner_container"><div class="slds-spinner slds-spinner_medium" role="status">' 41 + '<span class="slds-assistive-text">Loading</span><div class="slds-spinner__dot-a"></div><div class="slds-spinner__dot-b"></div>' 42 + '</div></div></div>'; 43 44 function waitForBody(timeoutMs, intervalMs){ 45 timeoutMs = typeof timeoutMs === 'number' ? timeoutMs : 5000; 46 intervalMs = typeof intervalMs === 'number' ? intervalMs : 50; 47 return new Promise(function(resolve, reject){ 48 var start = Date.now(); 49 (function poll(){ 50 if (document.body) return resolve(document.body); 51 if (Date.now() - start > timeoutMs) return reject(new Error("document.body did not appear")); 52 setTimeout(poll, intervalMs); 53 })(); 54 }); 55 } 56 function showSpinner(){ return waitForBody(5000,50).then(function(body){ if (!document.getElementById(SPINNER_ID)) body.insertAdjacentHTML('beforeend', SPINNER_HTML); log("Spinner shown"); }).catch(function(e){ warn("Spinner insert failed:", e && e.message); }); } 57 function removeSpinner(){ try { var s = document.getElementById(SPINNER_ID); if (s && s.parentNode) s.parentNode.removeChild(s); log("Spinner removed"); } catch(e){ warn("removeSpinner error:", e); } } 58 59 function cleanupDuplicateTargets(){ 60 try { 61 var all = Array.from(document.querySelectorAll('#' + TARGET_ID)); 62 if (all.length <= 1) return; 63 log("cleanup: found " + all.length + " targets, removing extras"); 64 for (var i = 1; i < all.length; i++) try { all[i].parentNode.removeChild(all[i]); } catch(e){} 65 } catch(e){ warn("cleanupDuplicateTargets error:", e); } 66 } 67 68 function ensureMount(){ 69 cleanupDuplicateTargets(); 70 var existing = document.getElementById(TARGET_ID); 71 if (existing) return existing; 72 function insert(){ 73 if (!document.body) return false; 74 if (document.getElementById(TARGET_ID)) return document.getElementById(TARGET_ID); 75 var el = document.createElement('div'); 76 el.id = TARGET_ID; 77 el.style.minHeight = "1px"; 78 el.setAttribute('data-head-managed','true'); 79 if (document.body.firstChild) document.body.insertBefore(el, document.body.firstChild); 80 else document.body.appendChild(el); 81 log("mount injected into body:", TARGET_ID); 82 return el; 83 } 84 if (document.readyState === 'interactive' || document.readyState === 'complete') return insert(); 85 return new Promise(function(resolve){ 86 document.addEventListener('DOMContentLoaded', function onDom(){ document.removeEventListener('DOMContentLoaded', onDom); resolve(insert()); }); 87 var obs = new MutationObserver(function(){ if (document.body) { try{ obs.disconnect(); }catch(e){}; resolve(insert()); } }); 88 obs.observe(document.documentElement, { childList:true, subtree:true }); 89 setTimeout(function(){ try{ obs.disconnect(); }catch(e){}; resolve(insert()); }, 5000); 90 }); 91 } 92 93 function observeAuraScripts(onFound){ 94 try { 95 var found = false;
96 var observer = new MutationObserver(function(muts){ 97 muts.forEach(function(m){ 98 if (!m.addedNodes) return; 99 m.addedNodes.forEach(function(n){ 100 if (n.tagName === 'SCRIPT') { 101 var src = n.src || ''; 102 if (/aura|aura_prod|lightning\.out/i.test(src) || /aura|aura_prod/i.test(n.textContent || '')) { 103 if (!found) { found = true; try { observer.disconnect(); } catch(e){}; onFound(src || "(inline)"); } 104 } 105 } 106 }); 107 }); 108 }); 109 observer.observe(document.head || document.documentElement, { childList: true, subtree: true }); 110 var scripts = Array.from(document.getElementsByTagName('script')); 111 for (var i=0;i<scripts.length;i++){ 112 var s = scripts[i]; 113 if (/aura|aura_prod|lightning\.out/i.test(s.src || '') || /aura|aura_prod/i.test(s.textContent || '')) { 114 try { observer.disconnect(); } catch(e){}; onFound(s.src || "(inline)"); break; 115 } 116 } 117 return function cancel(){ try{ observer.disconnect(); }catch(e){}; }; 118 } catch(e){ warn("observeAuraScripts error:", e); return function(){}; } 119 } 120 121 function targetHasAuraRenderedContent(){ 122 var t = document.getElementById(TARGET_ID); 123 if (!t) return false; 124 if (t.children.length > 0) return true; 125 try { if (t.querySelector('[data-aura],[data-aura-rendered],[data-auraelement]')) return true; } catch(e){} 126 return false; 127 } 128 129 function resetForReopenIfNeeded(){ 130 try { 131 var created = !!window.__HeadCreated[COMP_NAME]; 132 var popupOpen = !!window.FONChampionPopupOpen; 133 var hasRendered = targetHasAuraRenderedContent(); 134 135 if (created && !popupOpen) { 136 if (!hasRendered) { 137 log("Previously created but popup closed + no rendered content â resetting registry to allow reopen"); 138 window.__HeadCreated[COMP_NAME] = false; 139 window.__HeadCreating[COMP_NAME] = false; 140 window.__HeadStarted = window.__HeadStarted || {}; 141 window.__HeadStarted[COMP_NAME] = false; 142 var t = document.getElementById(TARGET_ID); 143 if (t) { 144 t.removeAttribute('data-head-created'); 145 t.innerHTML = ''; 146 } 147 return; 148 } 149 150 try { 151 log("Previously created but popup closed and target still has rendered content â cleaning target to allow fresh create"); 152 var target = document.getElementById(TARGET_ID); 153 if (target) { 154 while (target.firstChild) { 155 try { target.removeChild(target.firstChild); } catch(e){ break; } 156 } 157 target.removeAttribute('data-head-created'); 158 target.removeAttribute('data-head-managed'); 159 } 160 } catch(e){ warn("Error while cleaning target for reopen:", e); } 161 162 window.__HeadCreated[COMP_NAME] = false; 163 window.__HeadCreating[COMP_NAME] = false; 164 window.__HeadStarted = window.__HeadStarted || {}; 165 window.__HeadStarted[COMP_NAME] = false; 166 } 167 } catch(e){ warn("resetForReopenIfNeeded error:", e); } 168 } 169 170 function tryCreateOnce(attrs){ 171 attrs = attrs || {}; 172 return new Promise(function(resolve, reject){ 173 try { 174 if (window.__HeadCreated[COMP_NAME]) return resolve(null); 175 if (targetHasAuraRenderedContent()) { window.__HeadCreated[COMP_NAME] = true; return resolve(null); } 176 if (window.__HeadCreating[COMP_NAME]) { log("Another creator running â skipping"); return resolve(null); } 177 window.__HeadCreating[COMP_NAME] = true; 178 179 if (!window.$Lightning || typeof window.$Lightning.createComponent !== 'function') { 180 window.__HeadCreating[COMP_NAME] = false; 181 return reject(new Error("$Lightning.createComponent not present")); 182 } 183 184 window.$Lightning.createComponent(COMP_NAME, attrs, TARGET_ID, function(cmp){ 185 try { 186 window.__HeadCreated[COMP_NAME] = true; 187 var target = document.getElementById(TARGET_ID); 188 if (target) target.setAttribute('data-head-created', COMP_NAME); 189 } catch(e){} 190 window.__HeadCreating[COMP_NAME] = false;
191 resolve(cmp); 192 }); 193 194 } catch(e){ 195 try { window.__HeadCreating[COMP_NAME] = false; } catch(_){} 196 reject(e); 197 } 198 }); 199 } 200 201 function tryCreateLoop(attrs, onSuccess, onFailure){ 202 resetForReopenIfNeeded(); 203 204 if (window.__HeadCreated[COMP_NAME]) { log("Already created - skipping"); removeSpinner(); if (onSuccess) onSuccess(null); return function(){}; } 205 if (targetHasAuraRenderedContent() || window.FONChampionPopupOpen) { window.__HeadCreated[COMP_NAME] = true; removeSpinner(); if (onSuccess) onSuccess(null); return function(){}; } 206 207 showSpinner(); 208 209 var attempts = 0; 210 var cancelObserver = observeAuraScripts(function(){ log("Aura script observed"); }); 211 var timer = setInterval(function(){ 212 attempts++; 213 if (window.__HeadCreated[COMP_NAME] || targetHasAuraRenderedContent() || window.FONChampionPopupOpen) { 214 clearInterval(timer); try { cancelObserver(); } catch(e){}; removeSpinner(); if (onSuccess) onSuccess(null); return; 215 } 216 217 try { 218 log("Attempting createComponent (attempt " + attempts + "/" + MAX_CREATE_ATTEMPTS + ")"); 219 tryCreateOnce(attrs).then(function(cmp){ 220 if (!cmp) { 221 log("Create no-op (other creator handled it)."); window.__HeadCreated[COMP_NAME] = true; clearInterval(timer); try { cancelObserver(); } catch(e){}; removeSpinner(); if (onSuccess) onSuccess(null); return; 222 } 223 clearInterval(timer); try { cancelObserver(); } catch(e){}; removeSpinner(); log("SUCCESS: component created", cmp); window.__HeadCreated[COMP_NAME] = true; if (onSuccess) onSuccess(cmp); 224 }).catch(function(e){ 225 warn("create attempt threw:", e && e.message ? e.message : e); 226 if (attempts >= MAX_CREATE_ATTEMPTS) { clearInterval(timer); try { cancelObserver(); } catch(e){}; removeSpinner(); if (onFailure) onFailure(e); } 227 }); 228 } catch(eouter){ 229 warn("outer error:", eouter); 230 if (attempts >= MAX_CREATE_ATTEMPTS) { clearInterval(timer); try { cancelObserver(); } catch(e){}; removeSpinner(); if (onFailure) onFailure(eouter); } 231 } 232 }, CREATE_RETRY_MS); 233 234 return function cancel(){ clearInterval(timer); try { cancelObserver(); } catch(e){}; }; 235 } 236 237 function attachCheckboxWatcher() { 238 var cb = document.querySelector(CHECK_SELECTOR); 239 if (cb) { log("Field found in DOM."); attachOnce(cb); return; } 240 241 var found = false; 242 var obs = new MutationObserver(function(muts){ 243 for (var i=0;i<muts.length;i++){ 244 var m = muts[i]; 245 if (!m.addedNodes) continue; 246 for (var j=0;j<m.addedNodes.length;j++){ 247 var n = m.addedNodes[j]; 248 if (n.nodeType !== 1) continue; 249 try { 250 if (n.matches && n.matches(CHECK_SELECTOR)) { found = true; obs.disconnect(); attachOnce(n); return; } 251 var desc = n.querySelector && n.querySelector(CHECK_SELECTOR); 252 if (desc) { found = true; obs.disconnect(); attachOnce(desc); return; } 253 } catch(e){} 254 } 255 } 256 }); 257 obs.observe(document.documentElement || document, { childList:true, subtree:true }); 258 setTimeout(function(){ try{ obs.disconnect(); }catch(e){}; if (!found) log("Field not found within timeout"); }, 30000); 259 } 260 261 // UPDATED for Yes/No support 262 function attachOnce(fieldEl) { 263 if (!fieldEl) return; 264 if (fieldEl.__headWatcherAttached) { log("Watcher already attached for", fieldEl.tagName, fieldEl.type); return; } 265 fieldEl.__headWatcherAttached = true; 266 267 function shouldTrigger(el) { 268 var tag = (el.tagName || '').toLowerCase(); 269 var type = (el.type || '').toLowerCase(); 270 var val = (el.value || '').toString().toLowerCase(); 271 272 if (type === 'checkbox') { 273 log("Evaluating as checkbox. checked =", !!el.checked); 274 return !!el.checked; 275 } 276 log("Evaluating as non-checkbox. value =", val); 277 return (val === 'yes' || val === 'true' || val === '1'); 278 } 279 280 fieldEl.addEventListener('change', function(ev){ 281 try { 282 log("Field changed â tag:", fieldEl.tagName, "type:", fieldEl.type, "value:", fieldEl.value); 283 if (shouldTrigger(fieldEl)) { 284 resetForReopenIfNeeded(); 285 triggerCreate(); 286 } else { 287 log("Condition not met â no action."); 288 } 289 } catch(e){ warn("change handler error:", e); } 290 }, { once: false }); 291 292 if (shouldTrigger(fieldEl)) { 293 resetForReopenIfNeeded(); 294 triggerCreate(); 295 } 296 } 297 298 window.__HeadStarted = window.__HeadStarted || {}; 299 300 function triggerCreate() { 301 if (window.__HeadStarted[COMP_NAME]) { log("triggerCreate called but already started (global)"); return; } 302 window.__HeadStarted[COMP_NAME] = true; 303 304 var mountRes = ensureMount(); 305 var p = (mountRes && typeof mountRes.then === 'function') ? mountRes : Promise.resolve(mountRes); 306 p.then(function(){ 307 var attrs = { requiredParam: "", requiredValue: "", requiredUrlSubstring: "", substringCaseSensitive: false };
308 try { 309 var meta = document.querySelector('meta[name="recordId"],meta[name="sfdc-recordId"]'); 310 if (meta && meta.content) attrs.recordId = meta.content; 311 else { var q = new URLSearchParams(window.location.search); attrs.recordId = q.get('id') || q.get('recordId') || null; } 312 } catch(e){} 313 log("Triggering create loop now with attrs:", attrs); 314 tryCreateLoop(attrs, function(cmp){ 315 log("create loop done", cmp); 316 }, function(err){ err("create loop failed", err); }); 317 }).catch(function(e){ 318 err("ensureMount failed:", e); 319 window.__HeadStarted[COMP_NAME] = false; 320 }); 321 } 322 323 try { attachCheckboxWatcher(); } catch(e){ warn("attachCheckboxWatcher error:", e); } 324 325})();
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.