PageSourceSearch

https://emlid.com/wp-content/themes/emlid/js/header.js?ver=30407

js emlid.com collected 2026-09-24 09:01:17 UTC 15,368 bytes, 505 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2  function loadScriptOnce(src, test) {
3    if (typeof test === 'function' && test()) {
4      return Promise.resolve();
5    }
6
7    return new Promise(function (resolve, reject) {
8      var existing = document.querySelector('script[data-emlid-src="' + src + '"], script[src="' + src + '"]');
9
10      if (existing) {
11        if (existing.dataset.loaded === 'true') {
12          resolve();
13          return;
14        }
15
16        existing.addEventListener('load', function () { resolve(); }, { once: true });
17        existing.addEventListener('error', reject, { once: true });
18        return;
19      }
20
21      var script = document.createElement('script');
22      script.src = src;
23      script.async = true;
24      script.defer = true;
25      script.dataset.emlidSrc = src;
26      script.onload = function () {
27        script.dataset.loaded = 'true';
28        resolve();
29      };
30      script.onerror = reject;
31      document.body.appendChild(script);
32    });
33  }
34
35  function initLazyHubspotDeveloperEmbeds() {
36    var embeds = Array.prototype.slice.call(document.querySelectorAll('.js-lazy-hubspot-developer'));
37    if (!embeds.length) {
38      return;
39    }
40
41    function hydrate(embed) {
42      if (embed.dataset.hsState === 'loading' || embed.dataset.hsState === 'loaded') {
43        return;
44      }
45
46      var scriptSrc = embed.dataset.hsScript;
47      if (!scriptSrc) {
48        return;
49      }
50
51      embed.dataset.hsState = 'loading';
52
53      loadScriptOnce(scriptSrc)
54        .then(function () {
55          embed.dataset.hsState = 'loaded';
56          embed.removeAttribute('aria-busy');
57        })
58        .catch(function () {
59          embed.dataset.hsState = '';
60          embed.removeAttribute('aria-busy');
61        });
62    }
63
64    if (window.location.hash === '#contacts') {
65      embeds.forEach(hydrate);
66      return;
67    }
68
69    document.querySelectorAll('a[href="#contacts"]').forEach(function (link) {
70      link.addEventListener('click', function () {
71        embeds.forEach(hydrate);
72      }, { once: true });
73    });
74
75    embeds.forEach(function (embed) {
76      embed.addEventListener('focusin', function () { hydrate(embed); }, { once: true });
77      embed.addEventListener('mouseenter', function () { hydrate(embed); }, { once: true });
78      embed.addEventListener('touchstart', function () { hydrate(embed); }, { once: true, passive: true });
79    });
80
81    if (!('IntersectionObserver' in window)) {
82      embeds.forEach(hydrate);
83      return;
84    }
85
86    embeds.forEach(function (embed) {
87      var observer = new IntersectionObserver(function (entries) {
88        entries.forEach(function (entry) {
89          if (!entry.isIntersecting) {
90            return;
91          }
92          observer.unobserve(entry.target);
93          hydrate(entry.target);
94        });
95      }, { rootMargin: embed.dataset.rootMargin || '250px 0px' });
96
97      observer.observe(embed);
98    });
99  }
100
101  function initHubspotBusinessEmailOverrides() {
102    var forms = Array.prototype.slice.call(document.querySelectorAll('.hs-form-html[data-business-email-error]'));
103    if (!forms.length) {
104      return;
105    }
106
107    forms.forEach(function (form) {
108      var customMessage = form.dataset.businessEmailError;
109      if (!customMessage) {
110        return;
111      }
112
113      function normalizeText(value) {
114        return (value || '').replace(/\s+/g, ' ').trim();
115      }
116
117      var domainPattern =
118        /\b[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+\b/i;
119
120      function updateMessages() {
121        var candidates = form.querySelectorAll(
122          '.hsfc-EmailField .hsfc-ErrorAlert, ' +
123            '.hsfc-EmailField .hsfc-RichText, ' +
124            '.hsfc-EmailField [id$="-error"], ' +
125            '.hsfc-EmailField .hsfc-ValidationAlert__Text, ' +
126            '.hsfc-EmailField .hs-error-msg, ' +
127            '.hsfc-EmailField .hsfc-ErrorText'
128        );
129
130        candidates.forEach(function (node) {
131          var text = normalizeText(node.textContent || '');
132          var lowerText = text.toLowerCase();
133          if (!lowerText) {
134            return;
135          }
136
137          var looksLikeBusinessEmailError =
138            domainPattern.test(text) ||
139            lowerText.indexOf('business email') !== -1 ||
140            lowerText.indexOf('enter valid business email address') !== -1 ||
141            lowerText.indexOf('please enter a business email address') !== -1 ||
142            lowerText.indexOf('please enter a valid work email address') !== -1 ||
143            lowerText.indexOf('valid work email') !== -1 ||
144            lowerText.indexOf('different email address') !== -1 ||
145            lowerText.indexOf('does not accept addresses from') !== -1;
146
147          if (!looksLikeBusinessEmailError) {
148            return;
149          }
150
151          var target =
152            node.matches('.hsfc-ValidationAlert__Text, .hs-error-msg, .hsfc-ErrorText')
153              ? node
154              : node.querySelector('.hsfc-ValidationAlert__Text, .hs-error-msg, .hsfc-ErrorText, p, span') || node;
155
156          if (normalizeText(target.textContent) !== customMessage) {
157            target.textContent = customMessage;
158          }
159        });
160      }
161
162      updateMessages();
163
164      if ('MutationObserver' in window) {
165        var observer = new MutationObserver(function () {
166          updateMessages();
167        });
168
169        observer.observe(form, {
170          childList: true,
171          subtree: true,
172          characterData: true
173        });
174      }
175    });
176  }
177
178  function initHubspotAutofillFixes() {
179    var formRoots = Array.prototype.slice.call(document.querySelectorAll('.site-work-hs-form .hs-form-html'));
180    if (!formRoots.length) {
181      return;
182    }
183
184    formRoots.forEach(function (root) {
185      var rafId = 0;
186      var syncTimeouts = [];
187
188      function getFieldColor(field) {
189        return field.closest('.main-cta--dark, .emlid-cta-form--dark')
190          ? { text: 'var(--white)' }
191          : { text: 'var(--black)' };
192      }
193
194      function syncField(field) {
195        if (!field || !field.style) {
196          return;
197        }
198
199        var colors = getFieldColor(field);
200
201        field.style.setProperty('background', 'transparent', 'important');
202        field.style.setProperty('background-color', 'transparent', 'important');
203        field.style.setProperty('background-image', 'none', 'important');
204        field.style.setProperty('-webkit-box-shadow', '0 0 0 1000px transparent inset', 'important');
205        field.style.setProperty('box-shadow', '0 0 0 1000px transparent inset', 'important');
206        field.style.setProperty('-webkit-transition', 'background-color 999999s ease-out 0s, color 999999s ease-out 0s', 'important');
207        field.style.setProperty('transition', 'background-color 999999s ease-out 0s, color 999999s ease-out 0s', 'important');
208        field.style.setProperty('color', colors.text, 'important');
209        field.style.setProperty('caret-color', colors.text, 'important');
210      }
211
212      function syncRoot() {
213        root.querySelectorAll('.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-SelectInput').forEach(syncField);
214      }
215
216      function clearQueuedSyncs() {
217        if (rafId) {
218          cancelAnimationFrame(rafId);
219          rafId = 0;
220        }
221
222        syncTimeouts.forEach(function (id) {
223          clearTimeout(id);
224        });
225        syncTimeouts = [];
226      }
227
228      function queueSync() {
229        clearQueuedSyncs();
230        rafId = requestAnimationFrame(syncRoot);
231        [120, 320, 650, 1100].forEach(function (delay) {
232          syncTimeouts.push(window.setTimeout(syncRoot, delay));
233        });
234      }
235
236      root.addEventListener('focusin', function (event) {
237        if (event.target && event.target.matches && event.target.matches('.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-SelectInput')) {
238          syncField(event.target);
239        }
240      });
241
242      root.addEventListener('input', function (event) {
243        if (event.target && event.target.matches && event.target.matches('.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-SelectInput')) {
244          syncField(event.target);
245        }
246      });
247
248      root.addEventListener('change', function (event) {
249        if (event.target && event.target.matches && event.target.matches('.hsfc-TextInput, .hsfc-TextareaInput, .hsfc-SelectInput')) {
250          syncField(event.target);
251        }
252      });
253
254      root.addEventListener('click', function (event) {
255        if (!event.target || !event.target.closest) {
256          return;
257        }
258
259        if (event.target.closest('.hsfc-Button, .hsfc-NavigationRow__Buttons button')) {
260          queueSync();
261        }
262      });
263
264      syncRoot();
265      queueSync();
266
267      if ('MutationObserver' in window) {
268        var observer = new MutationObserver(function () {
269          queueSync();
270        });
271
272        observer.observe(root, {
273          childList: true,
274          subtree: true,
275          attributes: true,
276          attributeFilter: ['class', 'style', 'value']
277        });
278      }
279    });
280  }
281
282  function initHubspotAutocompleteDisabler() {
283    var formRoots = Array.prototype.slice.call(document.querySelectorAll('.hs-form-html[data-disable-autocomplete="true"]'));
284    if (!formRoots.length) {
285      return;
286    }
287
288    formRoots.forEach(function (root) {
289      var reapplyTimeouts = [];
290
291      function clearReapply() {
292        reapplyTimeouts.forEach(function (id) {
293          clearTimeout(id);
294        });
295        reapplyTimeouts = [];
296      }
297
298      function ensureDecoys(form) {
299        if (!form || form.querySelector('.cta-autocomplete-decoy')) {
300          return;
301        }
302
303        var wrap = document.createElement('div');
304        wrap.className = 'cta-autocomplete-decoy';
305        wrap.setAttribute('aria-hidden', 'true');
306        wrap.style.cssText = 'position:absolute;
306left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none;';
307
308        var username = document.createElement('input');
309        username.type = 'text';
310        username.name = 'cta_decoy_username';
311        username.autocomplete = 'username';
312        username.tabIndex = -1;
313
314        var email = document.createElement('input');
315        email.type = 'email';
316        email.name = 'cta_decoy_email';
317        email.autocomplete = 'email';
318        email.tabIndex = -1;
319
320        var password = document.createElement('input');
321        password.type = 'password';
322        password.name = 'cta_decoy_password';
323        password.autocomplete = 'current-password';
324        password.tabIndex = -1;
325
326        wrap.appendChild(username);
327        wrap.appendChild(email);
328        wrap.appendChild(password);
329        form.insertBefore(wrap, form.firstChild);
330      }
331
332      function applyGuards() {
333        var form = root.querySelector('form');
334        if (form) {
335          form.setAttribute('autocomplete', 'off');
336          ensureDecoys(form);
337        }
338
339        root.querySelectorAll('input, textarea, select').forEach(function (field) {
340          if (field.closest('.cta-autocomplete-decoy')) {
341            return;
342          }
343
344          if (!field || field.disabled || field.type === 'hidden') {
345            return;
346          }
347
348          var tagName = (field.tagName || '').toLowerCase();
349          var type = (field.getAttribute('type') || '').toLowerCase();
350
351          field.setAttribute('autocorrect', 'off');
352          field.setAttribute('autocapitalize', 'off');
353          field.setAttribute('spellcheck', 'false');
354          field.setAttribute('data-lpignore', 'true');
355          field.setAttribute('data-1p-ignore', 'true');
356          field.setAttribute('data-form-type', 'other');
357
358          if (tagName === 'select' || tagName === 'textarea') {
359            field.setAttribute('autocomplete', 'off');
360            return;
361          }
362
363          if (tagName === 'input' && (type === 'text' || type === 'email' || type === 'search' || type === 'tel' || type === 'url')) {
364            field.setAttribute('autocomplete', 'new-password');
365          } else {
366            field.setAttribute('autocomplete', 'off');
367          }
368        });
369      }
370
371      function queueApply() {
372        clearReapply();
373        applyGuards();
374        [120, 320, 650, 1100].forEach(function (delay) {
375          reapplyTimeouts.push(window.setTimeout(applyGuards, delay));
376        });
377      }
378
379      root.addEventListener('click', function (event) {
380        if (!event.target || !event.target.closest) {
381          return;
382        }
383
384        if (event.target.closest('.hsfc-Button, .hsfc-NavigationRow__Buttons button')) {
385          queueApply();
386        }
387      });
388
389      queueApply();
390
391      if ('MutationObserver' in window) {
392        var observer = new MutationObserver(function () {
393          queueApply();
394        });
395
396        observer.observe(root, {
397          childList: true,
398          subtree: true,
399          attributes: true,
400          attributeFilter: ['class', 'style', 'value']
401        });
402      }
403    });
404  }
405
406  initLazyHubspotDeveloperEmbeds();
407  initHubspotAutofillFixes();
408  initHubspotAutocompleteDisabler();
409  initHubspotBusinessEmailOverrides();
410
411  var burger = document.querySelector('.header__burger-toggle');
412  var nav = document.querySelector('.header__nav');
413  var header = document.querySelector('header');
414
415  if (!burger || !nav || !header) {
416    return;
417  }
418
419  var submenuItems = document.querySelectorAll('.header__menu-item--has-submenu');
420  var nextElem = header.nextElementSibling;
421
422  if (nextElem) {
423    nextElem.style.transition = 'margin-top 0.3s ease';
424  }
425
426  function syncOffset() {
427    if (window.innerWidth > 1200) {
428      if (nextElem) {
429        nextElem.style.marginTop = '0';
430      }
431      return;
432    }
433
434    if (!header.classList.contains('fixed-top') && nextElem && nav.classList.contains('header__nav--open')) {
435      requestAnimationFrame(function () {
436        nextElem.style.marginTop = nav.offsetHeight + 'px';
437      });
438    }
439  }
440
441  function openMenu() {
442    nav.classList.add('header__nav--open');
443    burger.classList.add('header__burger-toggle--open');
444    burger.setAttribute('aria-expanded', 'true');
445    syncOffset();
446  }
447
448  function closeMenu() {
449    nav.classList.remove('header__nav--open');
450    burger.classList.remove('header__burger-toggle--open');
451    burger.setAttribute('aria-expanded', 'false');
452
453    if (nextElem) {
454      nextElem.style.marginTop = '0';
455    }
456
457    submenuItems.forEach(function (item) {
458      item.classList.remove('header__menu-item--open');
459    });
460  }
461
462  burger.addEventListener('click', function () {
463    if (nav.classList.contains('header__nav--open')) {
464      closeMenu();
465    } else {
466      openMenu();
467    }
468  });
469
470  submenuItems.forEach(function (item) {
471    var link = item.querySelector('.header__menu-link');
472
473    if (!link) {
474      return;
475    }
476
477    link.addEventListener('click', function (e) {
478      if (window.innerWidth >= 1200) {
479        return;
480      }
481
482      e.preventDefault();
483
484      submenuItems.forEach(function (otherItem) {
485        if (otherItem !== item) {
486          otherItem.classList.remove('header__menu-item--open');
487        }
488      });
489
490      item.classList.toggle('header__menu-item--open');
491      syncOffset();
492    });
493  });
494
495  window.addEventListener('resize', function () {
496    if (window.innerWidth > 1200) {
497      closeMenu();
498      return;
499    }
500
501    if (nav.classList.contains('header__nav--open')) {
502      syncOffset();
503    }
504  });
505});

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.