PageSourceSearch

https://cardcompass.app/newsletter-popup.js

js cardcompass.app collected 2026-10-02 01:12:58 UTC 11,852 bytes, 212 lines download raw bytes

1(function () {
2  'use strict';
3  var SITEKEY = '0x4AAAAAADiVOynXw_ZhYDP0';
4  var EXCLUDED = /^\/(login|get-started|account|quiz)(\.html)?\/?$/;
5  var MIN_DELAY = 20000, TIME_TRIGGER = 75000, RETRY = 20000, DISMISS_MS = 7 * 864e5;
6  var BTN = 'Get deal alerts';
7  var MAIL = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 7L2 7"/></svg>';
8  var CHECK = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>';
9  var CSS = '.ccnl{position:fixed;right:24px;bottom:24px;width:360px;max-width:calc(100vw - 48px);box-sizing:border-box;background:#fff;border:1px solid var(--border,#E2E8F0);border-radius:var(--r-lg,20px);box-shadow:0 16px 48px rgba(7,30,74,.25);padding:24px;z-index:2100;font-family:inherit;color:var(--text-dark,#1A1A2E);opacity:0;transform:translateY(24px);transition:transform .35s cubic-bezier(.2,.8,.2,1),opacity .35s cubic-bezier(.2,.8,.2,1)}' +
10    '.ccnl.ccnl-in{opacity:1;transform:none}' +
11    '.ccnl-x{position:absolute;top:10px;right:10px;width:32px;height:32px;border:0;background:none;border-radius:50%;color:var(--text-light,#718096);font:inherit;font-size:22px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}' +
12    '.ccnl-x:hover{background:var(--bg-light,#F7F9FC);color:var(--text-dark,#1A1A2E)}' +
13    '.ccnl-eyebrow{display:flex;align-items:center;gap:7px;font-size:12px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--primary,#0B2D6B);margin:0 0 10px}' +
14    '.ccnl-eyebrow svg{width:16px;height:16px;flex-shrink:0;color:var(--accent-gold,#F5A623)}' +
15    '.ccnl h3{font-size:19px;font-weight:800;letter-spacing:-.3px;line-height:1.25;margin:0 0 8px;color:var(--primary,#0B2D6B)}' +
16    '.ccnl-main>p{font-size:14px;line-height:1.55;color:var(--text-gray,#4A5568);margin:0 0 16px}' +
17    '.ccnl input{width:100%;box-sizing:border-box;height:44px;padding:0 14px;border:1.5px solid var(--border,#E2E8F0);border-radius:10px;font:inherit;font-size:15px;color:inherit;outline:none;background:#fff}' +
18    '.ccnl input:focus{border-color:var(--accent,#1E7FD4);box-shadow:0 0 0 3px rgba(30,127,212,.18)}' +
19    '.ccnl-err{display:none;color:#DC2626;font-size:13px;margin:6px 0 0}.ccnl-err.on{display:block}' +
20    '.ccnl-ts{margin-top:10px}.ccnl-ts:empty{margin:0}' +
21    '.ccnl-btn{width:100%;height:46px;margin-top:12px;border:0;border-radius:10px;background:var(--accent,#1E7FD4);color:#fff;font:inherit;font-size:15px;font-weight:700;cursor:pointer;transition:background .2s,transform .2s}' +
22    '.ccnl-btn:hover{background:var(--accent-light,#4BA3F0);transform:translateY(-1px)}.ccnl-btn:disabled{opacity:.7;cursor:default;transform:none}' +
23    '.ccnl-ok{display:flex;align-items:center;gap:12px;font-size:15px;font-weight:600;color:var(--primary,#0B2D6B);padding:6px 0}' +
24    '.ccnl-ok svg{width:36px;height:36px;flex-shrink:0;color:var(--accent,#1E7FD4)}' +
25    '@media (max-width:640px){.ccnl{left:12px;right:12px;bottom:12px;width:auto;max-width:none;padding:18px 16px 16px}.ccnl-eyebrow{display:none}.ccnl h3{font-size:17px;padding-right:28px}.ccnl p{font-size:13px;margin-bottom:12px}.ccnl-x{width:40px;height:40px;top:4px;right:4px}}' +
26    '@media (prefers-reduced-motion:reduce){.ccnl{transition:none;transform:none}}';
27  var HTML = '<button class="ccnl-x" type="button" aria-label="Close">&times;</button>' +
28    '<div class="ccnl-main"><div class="ccnl-eyebrow">' + MAIL + 'Deal alerts</div>' +
29    '<h3 id="ccnl-title">Never miss a big sign-up bonus</h3>' +
30    '<p>An alert when a welcome bonus jumps, plus a monthly roundup of our top picks. Free, no spam, unsubscribe anytime.</p>' +
31    '<form novalidate><input type="email" name="email" autocomplete="email" inputmode="email" placeholder="[email protected]" aria-label="Email address" required>' +
32    '<p class="ccnl-err" aria-live="polite"></p><div class="ccnl-ts"></div>' +
33    '<button class="ccnl-btn" type="submit">' + BTN + '</button></form></div>';
34
35  var root = null, widgetId = null, token = '', tsDead = false;
36
37  function ls(k) { try { return localStorage.getItem(k); } catch (e) { return null; } }
38  function ss(k) { try { return sessionStorage.getItem(k); } catch (e) { return null; } }
39  function setLs(k, v) { try { localStorage.setItem(k, v); } catch (e) {} }
40  function setSs(k, v) { try { sessionStorage.setItem(k, v); } catch (e) {} }
41  function track(name, params) {
42    if (typeof gtag !== 'function') return;
43    params = params || {};
44    var src = ss('cc_src');
45    if (src) params.src = src;
46    gtag('event', name, params);
47  }
48
49  function eligible() {
50    if (ls('cc_subscribed') || ss('cc_nl_shown')) return false;
51    var d = +ls('cc_nl_dismissed');
52    if (d && Date.now() - d < DISMISS_MS) return false;
53    if (window.innerWidth < 320 || EXCLUDED.test(location.pathname)) return false;
54    try {
55      var u = JSON.parse(ls('cc_user') || 'null');
56      if (u && (u.newsletter || u.subscribed)) return false;
57    } catch (e) {}
58    return true;
59  }
60  function inlineFormVisible() {
61    var el = document.getElementById('newsletter-wrap') || document.getElementById('guides-nl-wrap');
62    if (!el) return false;
63    var r = el.getBoundingClientRect();
64    return r.height > 0 && r.bottom > 0 && r.top < window.innerHeight;
65  }
66
67  function loadTurnstile(cb) {
68    if (window.turnstile) return cb();
69    if (!document.querySelector('script[src*="challenges.cloudflare.com/turnstile"]')) {
70      var s = document.createElement('script');
71      s.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
72      s.async = true;
73      document.head.appendChild(s);
74    }
75    var tries = 0, iv = setInterval(function () {
76      if (window.turnstile) { clearInterval(iv); cb(); }
77      else if (++tries > 100) { clearInterval(iv); tsDead = true; }
78    }, 100);
79  }
80  function renderTurnstile() {
81    if (!root) return;
82    var opts = {
83      sitekey: SITEKEY, appearance: 'interaction-only', size: 'flexible',
84      callback: function (t) { token = t; },
85      'expired-callback': function () { token = ''; },
86      'error-callback': function () { token = ''; tsDead = true; }
87    };
88    var el = root.querySelector('.ccnl-ts');
89    try { widgetId = window.turnstile.render(el, opts); }
90    catch (e) { opts.size = 'normal'; try { widgetId = window.turnstile.render(el, opts); } catch (e2) {} }
91  }
92  function tsCall(fn) {
93    if (widgetId === null || !window.turnstile || !window.turnstile[fn]) return null;
94    try { return window.turnstile[fn](widgetId); } catch (e) { return null; }
95  }
96
97  function showError(msg) {
98    var el = root.querySelector('.ccnl-err');
99    el.textContent = msg;
100    el.classList.add('on');
101  }
102  function submit(e) {
103    e.preventDefault();
104    var input = root.querySelector('input'), email = input.value.trim();
105    root.querySelector('.ccnl-err').classList.remove('on');
106    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { showError('Enter a valid email address.'); input.focus(); return; }
107    if (!token) token = tsCall('getResponse') || '';
108    if (!token && tsDead) { showError('Verification unavailable — please use the newsletter form on our homepage.'); root.querySelector('.ccnl-btn').disabled = true; return; }
109    if (!token) { showError('Verifying you’re human… try again in a second.'); tsCall('execute'); return; }
110    var btn = root.querySelector('.ccnl-btn');
111    btn.disabled = true;
112    btn.textContent = 'Subscribing…';
113    fetch('/api/subscribe', {
114      method: 'POST', headers: { 'Content-Type': 'application/json' },
115      body: JSON.stringify({ email: email, cfToken: token })
116    }).then(function (r) { return r.json(); }).then(function (d) {
117      if (!root) return;
118      if (d.status !== 'subscribed') throw new Error('bad response');
119      setLs('cc_subscribed', email);
120      track('newsletter_signup', { source: 'popup', page_path: location.pathname });
121      root.querySelector('.ccnl-main').innerHTML = '<div class="ccnl-ok" role="status">' + CHECK + 'You’re in. Watch your inbox.</div>';
122      setTimeout(function () { close(false); }, 4000);
123    }).catch(function () {
124      if (!root) return;
125      showError('Something went wrong — please try again.');
126      btn.disabled = false;
127      btn.textContent = BTN;
128      token = '';
129      tsCall('reset');
130    });
131  }
132
133  function onKey(e) { if (e.key === 'Escape') close(true); }
134  function open(trigger) {
135    if (root) return;
136    if (!document.getElementById('ccnl-css')) {
137      var st = document.createElement('style');
138      st.id = 'ccnl-css';
139      st.textContent = CSS;
140      document.head.appendChild(st);
141    }
142    root = document.createElement('div');
143    root.className = 'ccnl';
144    root.setAttribute('role', 'dialog');
145    root.setAttribute('aria-labelledby', 'ccnl-title');
146    root.innerHTML = HTML;
147    document.body.appendChild(root);
148    root.querySelector('.ccnl-x').addEventListener('click', function () { close(true); });
149    root.querySelector('form').addEventListener('submit', submit);
150    document.addEventListener('keydown', onKey);
151    setSs('cc_nl_shown', '1');
152    loadTurnstile(renderTurnstile);
153    requestAnimationFrame(function () { requestAnimationFrame(function () { root && root.classList.add('ccnl-in'); }); });
154    track('nl_popup_show', { trigger: trigger });
155  }
156  function close(dismissed) {
157    if (!root) return;
158    var el = root;
159    root = null;
160    el.classList.remove('ccnl-in');
161    document.removeEventListener('keydown', onKey);
162    setTimeout(function () { el.parentNode && el.parentNode.removeChild(el); }, 400);
163    tsCall('remove');
164    widgetId = null;
165    token = '';
166    if (dismissed) { setLs('cc_nl_dismissed', String(Date.now())); track('nl_popup_dismiss'); }
167  }
168
169  function arm() {
170    if (!eligible()) return;
171    var start = Date.now(), fired = false, timer = null, visibleMs = 0, since = Date.now();
172    var fine = window.matchMedia && matchMedia('(pointer: fine)').matches;
173    function attempt(trigger) {
174      if (!eligible()) return;
175      var cb = document.getElementById('cookie-banner'), a = document.activeElement;
176      var busy = (cb && cb.offsetHeight > 0) || (a && /^(INPUT|TEXTAREA|SELECT)$/.test(a.tagName)) || inlineFormVisible();
177      if (busy) { setTimeout(function () { attempt(trigger); }, RETRY); return; }
178      open(trigger);
179    }
180    function fire(trigger) {
181      if (fired || Date.now() - start < MIN_DELAY) return;
182      fired = true;
183      clearTimeout(timer);
184      window.removeEventListener('scroll', onScroll);
185      document.removeEventListener('mouseleave', onLeave);
186      document.removeEventListener('visibilitychange', onVis);
187      attempt(trigger);
188    }
189    function onScroll() {
190      var h = document.documentElement.scrollHeight - window.innerHeight;
191      if (h > 0 && window.scrollY / h >= 0.55) fire('scroll');
192    }
193    function onLeave(e) { if (e.clientY <= 0) fire('exit'); }
194    function onVis() {
195      if (document.visibilityState === 'visible') {
196        since = Date.now();
197        timer = setTimeout(function () { fire('time'); }, TIME_TRIGGER - visibleMs);
198      } else {
199        visibleMs += Date.now() - since;
200        clearTimeout(timer);
201      }
202    }
203    window.addEventListener('scroll', onScroll, { passive: true });
204    if (fine) document.addEventListener('mouseleave', onLeave);
205    document.addEventListener('visibilitychange', onVis);
206    if (document.visibilityState === 'visible') onVis();
207    setTimeout(onScroll, MIN_DELAY);
208  }
209
210  window.ccNewsletter = { open: function (trigger) { open(trigger || 'manual'); }, close: function () { close(true); } };
211  arm();
212})();

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.