1(function () { 2 'use strict'; 3 if (window.youGrowth) return; 4 5 var host = window.location.hostname.replace(/^www\./, ''); 6 var key = 'you:growth:v1:' + host; 7 var blocked = /^\/(admin|auth|dashboard|account|api)(\/|$)/; 8 var legal = /^\/(about|contact|privacy|privacy-policy|terms|terms-of-service|cookies?|cookie-policy|accessibility)(\/|$)/; 9 var toolPath = /(tools?|calculator|check-?up|quiz|test|generator|planner|assessment|tracker)/i.test(location.pathname); 10 var allowedEvents = ['page_view', 'return_visit', 'save', 'unsave', 'share', 'copy_link', 'resume', 'tool_complete', 'subscribe', 'dismiss_resume', 'push_granted', 'push_denied', 'push_subscribed', 'push_error']; 11 12 function readState() { 13 try { return JSON.parse(localStorage.getItem(key)) || {}; } catch (_) { return {}; } 14 } 15 function writeState(state) { 16 try { localStorage.setItem(key, JSON.stringify(state)); } catch (_) {} 17 } 18 function canonicalUrl() { 19 var canonical = document.querySelector('link[rel="canonical"]'); 20 return canonical ? canonical.href : location.origin + location.pathname; 21 } 22 function track(name, detail) { 23 if (allowedEvents.indexOf(name) === -1 || blocked.test(location.pathname)) return; 24 var body = JSON.stringify({event: name, path: location.pathname, detail: detail || {}}); 25 try { 26 if (navigator.sendBeacon) { 27 navigator.sendBeacon('/engagement/event', new Blob([body], {type: 'application/json'})); 28 } else { 29 fetch('/engagement/event', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: body, keepalive: true, credentials: 'same-origin'}); 30 } 31 } catch (_) {} 32 } 33 function node(tag, className, text) { 34 var element = document.createElement(tag); 35 if (className) element.className = className; 36 if (text) element.textContent = text; 37 return element; 38 } 39 function addStyles() { 40 var style = node('style'); 41 style.textContent = '.you-growth-actions{box-sizing:border-box;max-width:960px;margin:32px auto;padding:16px 18px;border:1px solid #d8dee8;border-radius:14px;background:#fff;color:#182230;box-shadow:0 8px 30px rgba(15,23,42,.07);font:600 14px/1.35 system-ui,-apple-system,sans-serif}.you-growth-actions__row{display:flex;flex-wrap:wrap;gap:10px;align-items:center}.you-growth-actions__label{margin-right:auto;font-weight:750}.you-growth-button,.you-growth-actions a{appearance:none;border:1px solid #b9c4d2;border-radius:999px;background:#fff;color:#182230;padding:9px 14px;font:700 13px/1 system-ui,-apple-system,sans-serif;text-decoration:none;cursor:pointer}.you-growth-button:hover,.you-growth-button:focus,.you-growth-actions a:hover,.you-growth-actions a:focus{border-color:#334155;background:#f1f5f9}.you-growth-nudge{margin:0 0 12px;padding:12px 14px;border-radius:10px;background:#f1f5f9;font-weight:500}.you-growth-resume{position:fixed;z-index:2147483000;left:16px;bottom:16px;box-sizing:border-box;width:min(380px,calc(100vw - 32px));padding:16px 44px 16px 16px;border:1px solid #d8dee8;border-radius:14px;background:#fff;color:#182230;box-shadow:0 16px 42px rgba(15,23,42,.2);font:14px/1.4 system-ui,-apple-system,sans-serif}.you-growth-resume strong{display:block;margin-bottom:7px}.you-growth-resume a{display:block;margin-top:5px;color:#0f766e;font-weight:750}.you-growth-resume button{position:absolute;top:8px;right:8px;border:0;background:transparent;font-size:20px;cursor:pointer}@media(max-width:520px){.you-growth-actions{margin:24px 12px}.you-growth-actions__label{width:100%}}'; 42 document.head.appendChild(style); 43 } 44 function usefulPage() { 45 if (blocked.test(location.pathname) || legal.test(location.pathname)) return false; 46 if (location.pathname === '/') { 47 return !!document.querySelector('[data-result], .result-panel, .checkup-result, .mini-result, .calc-result, .result-box'); 48 } 49 return !!document.querySelector('main article, article, [itemtype*="Article"]') || /(blog|learn|guides?|articles?|tools?|pickup-guide|personality|insurance|security|communication|relationships?|credit|debt)/i.test(location.pathname); 50 } 51 function rememberPage(state) { 52 if (!usefulPage()) return; 53 var item = {path: location.pathname, title: document.title.replace(/\s*[|â-]\s*[^|â-]+$/, '').trim(), seen: Date.now()}; 54 state.recent = (state.recent || []).filter(function (entry) { return entry.path !== item.path; }); 55 state.recent.unshift(item); 56 state.recent = state.recent.slice(0, 12); 57 } 58 function addActions(state) { 59 if (!usefulPage()) return null; 60 var main = document.querySelector('main'); 61 if (!main || document.querySelector('.you-growth-actions')) return null; 62 var box = node('aside', 'you-growth-actions'); 63 box.setAttribute('aria-label', 'Save and share this page'); 64 var row = node('div', 'you-growth-actions__row'); 65 row.appendChild(node('span', 'you-growth-actions__label', 'Keep this useful page handy')); 66 var saved = (state.saved || []).some(function (entry) { return entry.path === location.pathname; }); 67 var saveButton = node('button', 'you-growth-button', saved ? 'Saved' : 'Save'); 68 saveButton.type = 'button'; 69 saveButton.addEventListener('click', function () { 70 state.saved = state.saved || []; 71 var index = state.saved.findIndex(function (entry) { return entry.path === location.pathname; }); 72 if (index >= 0) { 73 state.saved.splice(index, 1); saveButton.textContent = 'Save'; track('unsave'); 74 } else { 75 state.saved.unshift({path: location.pathname, title: document.title, saved: Date.now()}); 76 state.saved = state.saved.slice(0, 25); saveButton.textContent = 'Saved'; track('save'); 77 } 78 writeState(state); 79 }); 80 row.appendChild(saveButton); 81 if (navigator.share) { 82 var shareButton = node('button', 'you-growth-button', 'Share'); 83 shareButton.type = 'button'; 84 shareButton.addEventListener('click', function () { 85 navigator.share({title: document.title, text: document.querySelector('meta[name="description"]')?.content || '', url: canonicalUrl()}).then(function () { track('share', {method: 'native'}); }).catch(function () {}); 86 }); 87 row.appendChild(shareButton); 88 } 89 var copyButton = node('button', 'you-growth-button', 'Copy link');
90 copyButton.type = 'button'; 91 copyButton.addEventListener('click', function () { 92 navigator.clipboard.writeText(canonicalUrl()).then(function () { 93 copyButton.textContent = 'Link copied'; track('copy_link'); 94 setTimeout(function () { copyButton.textContent = 'Copy link'; }, 1800); 95 }).catch(function () { window.prompt('Copy this link', canonicalUrl()); }); 96 }); 97 row.appendChild(copyButton); 98 box.appendChild(row); 99 main.appendChild(box); 100 return box; 101 } 102 function showResume(state) { 103 if (location.pathname !== '/') return; 104 if (Date.now() - (state.resumeDismissed || 0) < 7 * 86400000) return; 105 var isSaved = state.saved && state.saved.length; 106 var items = (isSaved ? state.saved : (state.recent || [])).filter(function (entry) { return entry.path !== '/'; }).slice(0, 3); 107 if (!items.length) return; 108 setTimeout(function () { 109 var box = node('aside', 'you-growth-resume'); 110 box.appendChild(node('strong', '', isSaved ? 'Your saved pages' : 'Continue where you left off')); 111 items.forEach(function (item) { 112 var link = node('a', '', item.title || 'Open your recent page'); link.href = item.path; 113 link.addEventListener('click', function () { track('resume', {source: isSaved ? 'saved' : 'recent'}); }); box.appendChild(link); 114 }); 115 var close = node('button', '', 'Ã'); close.type = 'button'; close.setAttribute('aria-label', 'Dismiss'); 116 close.addEventListener('click', function () { state.resumeDismissed = Date.now(); writeState(state); box.remove(); track('dismiss_resume'); }); 117 box.appendChild(close); document.body.appendChild(box); 118 }, 1400); 119 } 120 function addCompletionNudge(actions) { 121 if (!actions || actions.querySelector('.you-growth-nudge')) return; 122 var nudge = node('div', 'you-growth-nudge', 'Result ready. Save this page so you can return, or share it with someone who would find it useful.'); 123 if (host === 'good.you' || host === 'like.you') { 124 var link = node('a', '', 'Get occasional useful updates'); 125 link.href = host === 'good.you' ? '/newsletter' : '#newsletter-title'; 126 link.style.marginLeft = '10px'; link.addEventListener('click', function () { track('subscribe'); }); nudge.appendChild(link); 127 } 128 actions.insertBefore(nudge, actions.firstChild); track('tool_complete'); 129 } 130 function observeResults(actions) { 131 if (!actions) return; 132 var selector = '[data-result], [data-test-result], .result-panel, .tool-result, .type-result, .checkup-result, .mini-result, .calc-result, .result-box, #result, #results'; 133 if (!toolPath && !document.querySelector(selector)) return; 134 function visibleResult() { 135 return Array.prototype.some.call(document.querySelectorAll(selector), function (element) { 136 return !element.hidden && !element.classList.contains('is-hidden') && getComputedStyle(element).display !== 'none' && element.textContent.trim().length > 20; 137 }); 138 } 139 if (visibleResult()) addCompletionNudge(actions); 140 var observer = new MutationObserver(function () { if (visibleResult()) { addCompletionNudge(actions); observer.disconnect(); } }); 141 observer.observe(document.body, {subtree: true, childList: true, attributes: true, attributeFilter: ['hidden', 'class', 'style']}); 142 document.addEventListener('submit', function () { setTimeout(function () { addCompletionNudge(actions); }, 500); }, {once: true}); 143 } 144 function init() { 145 if (blocked.test(location.pathname)) return; 146 addStyles(); 147 var state = readState(); 148 var now = Date.now(); 149 var previous = state.lastVisit || 0; 150 if (previous && now - previous > 20 * 3600000) { 151 var days = Math.round((now - previous) / 86400000); 152 track('return_visit', {bucket: days >= 30 ? '30d_plus' : days >= 7 ? '7_29d' : '1_6d'}); 153 } 154 state.lastVisit = now; rememberPage(state); writeState(state); track('page_view'); 155 var actions = addActions(state); showResume(state); observeResults(actions); 156 document.addEventListener('you:completed', function () { addCompletionNudge(actions); }); 157 document.querySelectorAll('form[action*="newsletter"], [data-newsletter]').forEach(function (form) { form.addEventListener('submit', function () { track('subscribe'); }); }); 158 } 159 window.youGrowth = {track: track, complete: function () { document.dispatchEvent(new CustomEvent('you:completed')); }}; 160 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); else init(); 161}());
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.