PageSourceSearch

https://www.simon-huck.de/assets/js/main.js

js simon-huck.de collected 2026-10-10 00:31:19 UTC 4,807 bytes, 114 lines download raw bytes

1/* Simon Huck – Website-Interaktionen (kein Framework, minimal) */
2(function () {
3  'use strict';
4
5  /* ---------- Anker-Sprung beim Laden reparieren ----------
6     Bug (gefunden 04.08.2026, siehe GOLIVE-CHECKLISTE.md): html { scroll-behavior: smooth }
7     bricht in Chrome das automatische Springen zum URL-Anker beim Seitenaufruf, weil
8     Bilder/Fonts während des Ladens die Scroll-Animation unterbrechen, bevor sie ankommt.
9     Betrifft z. B. kontakt.html→/#kontakt oder digital-check.html#zusammenarbeit.
10     Fix: nach vollständigem Laden manuell (ohne Smooth-Animation) zum Ziel springen. */
11  function scrollToHashOnLoad() {
12    if (!location.hash) return;
13    var id = decodeURIComponent(location.hash.slice(1));
14    var target = document.getElementById(id);
15    if (!target) return;
16    target.scrollIntoView({ behavior: 'auto', block: 'start' });
17  }
18  window.addEventListener('load', scrollToHashOnLoad);
19
20  /* ---------- Jahr im Footer ---------- */
21  document.querySelectorAll('[data-year]').forEach(function (el) {
22    el.textContent = new Date().getFullYear();
23  });
24
25  /* ---------- Mobile-Menü ---------- */
26  var mToggle = document.querySelector('[data-mobile-toggle]');
27  var mMenu = document.querySelector('[data-mobile-menu]');
28  if (mToggle && mMenu) {
29    mToggle.addEventListener('click', function () {
30      var open = mMenu.classList.toggle('hidden') === false;
31      mToggle.setAttribute('aria-expanded', String(open));
32    });
33  }
34
35  /* ---------- Dropdown (Tastatur-Zugänglichkeit; Hover per CSS) ---------- */
36  var ddToggle = document.querySelector('[data-dropdown-toggle]');
37  var ddMenu = document.querySelector('[data-dropdown-menu]');
38  if (ddToggle && ddMenu) {
39    ddToggle.addEventListener('click', function (e) {
40      e.preventDefault();
41      var open = ddMenu.classList.toggle('hidden') === false;
42      ddToggle.setAttribute('aria-expanded', String(open));
43    });
44    document.addEventListener('keydown', function (e) {
45      if (e.key === 'Escape') { ddMenu.classList.add('hidden'); ddToggle.setAttribute('aria-expanded', 'false'); }
46    });
47  }
48
49  /* ---------- Fly-In ----------
50     Das Fly-In (Foto + Termin-CTA) wird NICHT mehr im Code umgesetzt,
51     sondern als Pop-up-Formular direkt in HubSpot verwaltet und über das
52     HubSpot-Tracking-Skript ausgeliefert (Cookiebot-gated). Konfiguration:
53     siehe website-neu/HUBSPOT-FLYIN.md
54  */
55
56  /* ---------- HubSpot-Formular (Cookiebot-konform) ----------
57     Lädt das HubSpot-Formular erst nach Marketing-Consent.
58     Markup-Anker:  #hs-form-placeholder / #hs-form-container / [data-hs-load]
59  */
60  var HS = { region: 'eu1', portalId: '145327216', formId: '67758ebd-1db7-4225-adf9-0e5a96a7eaf7' };
61  var hsLoaded = false;
62
63  function loadHubSpotForm() {
64    if (hsLoaded) return;
65    var container = document.getElementById('hs-form-container');
66    if (!container) return;
67    hsLoaded = true;
68    var s = document.createElement('script');
69    s.src = 'https://js-eu1.hsforms.net/forms/embed/v2.js';
70    s.charset = 'utf-8';
71    s.type = 'text/javascript';
72    s.onload = function () {
73      if (!window.hbspt) return;
74      window.hbspt.forms.create({
75        region: HS.region,
76        portalId: HS.portalId,
77        formId: HS.formId,
78        target: '#hs-form-container',
79        cssClass: 'hs-form',
80        onFormSubmit: function () {
81          // Google-Ads-Conversion-Tracking (aus altem kontakt.html übernommen, 04.08.2026 –
82          // ging beim Rebuild verloren, siehe GOLIVE-CHECKLISTE.md).
83          if (window.__googleAdsLeadConversionFired) return;
84          if (typeof window.gtag !== 'function') return;
85          window.__googleAdsLeadConversionFired = true;
86          window.gtag('event', 'conversion', {
87            'send_to': 'AW-17523896240/iEBTCIGr_5EbELDfhaRB',
88            'value': 1.0,
89            'currency': 'EUR'
90          });
91        }
92      });
93    };
94    document.head.appendChild(s);
95  }
96  function revealForm() {
97    var ph = document.getElementById('hs-form-placeholder');
98    var c = document.getElementById('hs-form-container');
99    if (ph) ph.style.display = 'none';
100    if (c) c.style.display = 'block';
101    loadHubSpotForm();
102  }
103  function hasMarketingConsent() {
104    return typeof window.Cookiebot !== 'undefined' && window.Cookiebot.consent && window.Cookiebot.consent.marketing;
105  }
106  window.addEventListener('CookiebotOnLoad', function () { if (hasMarketingConsent()) revealForm(); });
107  window.addEventListener('CookiebotOnAccept', function () { if (hasMarketingConsent()) revealForm(); });
108  var loadBtn = document.querySelector('[data-hs-load]');
109  if (loadBtn) {
110    loadBtn.addEventListener('click', function () {
111      if (typeof window.Cookiebot !== 'undefined' && window.Cookiebot.show) window.Cookiebot.show();
112    });
113  }
114})();

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.