PageSourceSearch

https://airshopapp.com/js/cnc-magnet.js?v=20260913b

js airshopapp.com collected 2026-10-05 19:23:52 UTC 4,543 bytes, 150 lines download raw bytes

1/**
2 * CNC tool tags email magnet. Slides up after scroll, POSTs to AirShop.
3 */
4(function() {
5    var card = document.getElementById('cnc-magnet');
6    var form = document.getElementById('cnc-magnet-form');
7    var messageEl = document.getElementById('cnc-magnet-message');
8    var emailInput = document.getElementById('cnc-magnet-email');
9    var closeButtons = document.querySelectorAll('[data-cnc-magnet-close]');
10
11    if (!card || !form || !messageEl || !emailInput) return;
12
13    var STORAGE_DISMISS = 'airshop-cnc-magnet-dismissed';
14    var STORAGE_SUBMIT = 'airshop-cnc-magnet-submitted';
15    var MIN_MS = 8000;
16    var MIN_SCROLL = 0.4;
17    var formLoadTime = Date.now();
18    var shown = false;
19    var readyAt = Date.now() + MIN_MS;
20
21    function apiUrl() {
22        if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
23            return 'http://localhost:3000/api/leads/cnc-tool-tags-signup';
24        }
25        return 'https://airshop.work/api/leads/cnc-tool-tags-signup';
26    }
27
28    function alreadyDone() {
29        try {
30            return Boolean(
31                window.localStorage.getItem(STORAGE_DISMISS) ||
32                window.localStorage.getItem(STORAGE_SUBMIT)
33            );
34        } catch (err) {
35            return false;
36        }
37    }
38
39    function persist(key) {
40        try {
41            window.localStorage.setItem(key, '1');
42        } catch (err) {
43            /* ignore quota / private mode */
44        }
45    }
46
47    function hide() {
48        card.classList.remove('is-visible');
49        card.setAttribute('hidden', '');
50    }
51
52    function show() {
53        if (shown || alreadyDone()) return;
54        shown = true;
55        card.removeAttribute('hidden');
56        window.setTimeout(function() {
57            card.classList.add('is-visible');
58        }, 20);
59    }
60
61    function dismiss() {
62        persist(STORAGE_DISMISS);
63        hide();
64    }
65
66    function scrollProgress() {
67        var doc = document.documentElement;
68        var max = Math.max(doc.scrollHeight - window.innerHeight, 1);
69        return window.scrollY / max;
70    }
71
72    function maybeShow() {
73        if (shown || alreadyDone()) return;
74        if (Date.now() < readyAt) return;
75        if (scrollProgress() < MIN_SCROLL) return;
76        show();
77    }
78
79    if (alreadyDone()) {
80        hide();
81        return;
82    }
83
84    window.addEventListener('scroll', maybeShow, { passive: true });
85    window.setTimeout(maybeShow, MIN_MS);
86
87    closeButtons.forEach(function(button) {
88        button.addEventListener('click', dismiss);
89    });
90
91    document.addEventListener('keydown', function(event) {
92        if (event.key === 'Escape' && card.classList.contains('is-visible')) {
93            dismiss();
94        }
95    });
96
97    form.addEventListener('submit', async function(event) {
98        event.preventDefault();
99
100        var submitBtn = form.querySelector('button[type="submit"]');
101        var honeypot = form.querySelector('input[name="website"]');
102        var email = emailInput.value.trim();
103
104        if (honeypot && honeypot.value.trim()) {
105            return;
106        }
107
108        if (!email) {
109            messageEl.textContent = 'Please enter your email.';
110            messageEl.className = 'cnc-magnet-message error';
111            return;
112        }
113
114        submitBtn.disabled = true;
115        messageEl.textContent = '';
116        messageEl.className = 'cnc-magnet-message';
117
118        try {
119            var response = await fetch(apiUrl(), {
120                method: 'POST',
121                headers: { 'Content-Type': 'application/json' },
122                body: JSON.stringify({
123                    email: email,
124                    website: honeypot ? honeypot.value : '',
125                    form_load_time: formLoadTime,
126                    leadType: 'cnc_tool_tags'
127                })
128            });
129
130            var data = await response.json().catch(function() {
131                return {};
132            });
133
134            if (!response.ok) {
135                throw new Error(data.error || 'Something went wrong');
136            }
137
138            messageEl.textContent = 'Check your inbox.';
139            messageEl.className = 'cnc-magnet-message success';
140            form.reset();
141            persist(STORAGE_SUBMIT);
142            window.setTimeout(hide, 1800);
143        } catch (err) {
144            messageEl.textContent = err.message || 'Failed to sign up. Please try again.';
145            messageEl.className = 'cnc-magnet-message error';
146        } finally {
147            submitBtn.disabled = false;
148        }
149    });
150})();

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.