top of page
bottom of page
// =====================================================================
// VELOV — Performance Patch v1.0
// Install: Wix Editor → Settings → Custom Code → + Add Custom Code
// Place code in: BODY END
// Apply to: All pages
// =====================================================================
// What this does:
// 1. Adds loading="lazy" to every img below the fold (CWV improvement)
// 2. Adds decoding="async" to all images (parallel decode)
// 3. Promotes hero image (first img with class .hero or first viewport img)
// to fetchpriority="high" for faster LCP
// 4. Adds rel="noopener noreferrer" to external links missing it (security)
// 5. Auto-adds aria-label to icon-only buttons (a11y + SEO)
// =====================================================================
(function () {
'use strict';
// Wait for DOM (Wix renders progressively)
var ready = function (fn) {
if (document.readyState !== 'loading') fn();
else document.addEventListener('DOMContentLoaded', fn);
};
ready(function () {
// ----- 1. LAZY-LOAD IMAGES BELOW FOLD -----
var foldHeight = window.innerHeight || 800;
var imgs = document.querySelectorAll('img');
var firstImage = null;
imgs.forEach(function (img, idx) {
// Skip if already has loading attribute
if (!img.hasAttribute('loading')) {
var rect = img.getBoundingClientRect();
var isAboveFold = rect.top < foldHeight && rect.top >= -50;
img.setAttribute('loading', isAboveFold ? 'eager' : 'lazy');
}
// Decoding async on everything
if (!img.hasAttribute('decoding')) {
img.setAttribute('decoding', 'async');
}
// Track first image for fetchpriority
if (idx === 0 && !firstImage) firstImage = img;
});
// ----- 2. HERO IMAGE = FETCHPRIORITY HIGH -----
var hero =
document.querySelector('img.hero, [class*="hero"] img, .Hero img, header img') ||
firstImage;
if (hero && !hero.hasAttribute('fetchpriority')) {
hero.setAttribute('fetchpriority', 'high');
hero.setAttribute('loading', 'eager');
}
// ----- 3. EXTERNAL LINKS: noopener -----
var anchors = document.querySelectorAll('a[target="_blank"]');
anchors.forEach(function (a) {
var rel = a.getAttribute('rel') || '';
if (!/noopener/.test(rel) || !/noreferrer/.test(rel)) {
a.setAttribute('rel', (rel + ' noopener noreferrer').trim());
}
});
// ----- 4. ICON-ONLY BUTTONS GET ARIA-LABEL -----
var buttons = document.querySelectorAll('button, a[role="button"]');
buttons.forEach(function (btn) {
var text = (btn.textContent || '').trim();
var hasLabel = btn.hasAttribute('aria-label') || btn.hasAttribute('aria-labelledby');
if (!text && !hasLabel) {
var titleAttr = btn.getAttribute('title');
if (titleAttr) {
btn.setAttribute('aria-label', titleAttr);
}
}
});
// ----- 5. PRECONNECT TO WHATSAPP (warm connection) -----
var hasWaPreconnect = document.querySelector('link[rel="preconnect"][href*="wa.me"]');
if (!hasWaPreconnect) {
var link = document.createElement('link');
link.rel = 'preconnect';
link.href = 'https://wa.me';
document.head.appendChild(link);
}
// ----- 6. GA4 EVENT TRACKING (fires only if gtag present) -----
function trackEvent(eventName, params) {
if (typeof window.gtag === 'function') {
window.gtag('event', eventName, params || {});
}
}
// WhatsApp clicks
document.addEventListener('click', function (e) {
var target = e.target.closest('a[href*="wa.me"], a[href*="whatsapp"]');
if (target) {
trackEvent('whatsapp_click', {
link_url: target.href,
link_text: target.textContent.trim().slice(0, 100)
});
}
});
// Phone clicks
document.addEventListener('click', function (e) {
var target = e.target.closest('a[href^="tel:"]');
if (target) {
trackEvent('phone_click', { link_url: target.href });
}
});
// Pannendienst CTAs
document.addEventListener('click', function (e) {
var target = e.target.closest(
'a[href*="pannendienst"], a[href*="notfall"], button[data-cta="pannendienst"]'
);
if (target) {
trackEvent('pannendienst_cta', { source: window.location.pathname });
}
});
// Booking form submit
document.addEventListener('submit', function (e) {
var form = e.target;
if (form.matches('form[data-booking], form[id*="book"], form[class*="booking"]')) {
trackEvent('booking_form_submit', { form_id: form.id || 'unknown' });
}
});
// 75% scroll on homepage
if (window.location.pathname === '/' || window.location.pathname === '') {
var fired = false;
window.addEventListener(
'scroll',
function () {
if (fired) return;
var scrollDepth =
(window.scrollY + window.innerHeight) / document.documentElement.scrollHeight;
if (scrollDepth >= 0.75) {
fired = true;
trackEvent('scroll_75_homepage');
}
},
{ passive: true }
);
}
console.log('[VELOV] Performance + tracking patch loaded');
});
})();