PageSourceSearch

https://www.reiskosten-berekenen.nl/js/main.js

js reiskosten-berekenen.nl collected 2026-10-01 06:47:27 UTC 5,987 bytes, 189 lines download raw bytes

1// Main JavaScript for Reiskosten Berekenen
2
3// Mobile Menu Toggle
4document.addEventListener('DOMContentLoaded', function() {
5    const menuToggle = document.querySelector('.mobile-menu-toggle');
6    const navMenu = document.querySelector('.nav-menu');
7    
8    if (menuToggle && navMenu) {
9        menuToggle.addEventListener('click', function() {
10            navMenu.style.display = navMenu.style.display === 'flex' ? 'none' : 'flex';
11            navMenu.style.flexDirection = 'column';
12            navMenu.style.position = 'absolute';
13            navMenu.style.top = '100%';
14            navMenu.style.left = '0';
15            navMenu.style.right = '0';
16            navMenu.style.backgroundColor = 'white';
17            navMenu.style.padding = '1rem';
18            navMenu.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)';
19        });
20        
21        // Close menu when clicking outside
22        document.addEventListener('click', function(e) {
23            if (!menuToggle.contains(e.target) && !navMenu.contains(e.target)) {
24                if (window.innerWidth < 768) {
25                    navMenu.style.display = 'none';
26                }
27            }
28        });
29    }
30});
31
32// Smooth Scroll for Anchor Links
33document.querySelectorAll('a[href^="#"]').forEach(anchor => {
34    anchor.addEventListener('click', function(e) {
35        const href = this.getAttribute('href');
36        if (href !== '#' && href.length > 1) {
37            e.preventDefault();
38            const target = document.querySelector(href);
39            if (target) {
40                target.scrollIntoView({
41                    behavior: 'smooth',
42                    block: 'start'
43                });
44            }
45        }
46    });
47});
48
49// Lazy Load Images
50if ('IntersectionObserver' in window) {
51    const imageObserver = new IntersectionObserver((entries, observer) => {
52        entries.forEach(entry => {
53            if (entry.isIntersecting) {
54                const img = entry.target;
55                if (img.dataset.src) {
56                    img.src = img.dataset.src;
57                    img.removeAttribute('data-src');
58                    observer.unobserve(img);
59                }
60            }
61        });
62    });
63    
64    document.querySelectorAll('img[data-src]').forEach(img => {
65        imageObserver.observe(img);
66    });
67}
68
69// Form Input Validation Feedback
70document.querySelectorAll('input[type="number"]').forEach(input => {
71    input.addEventListener('invalid', function(e) {
72        e.preventDefault();
73        this.classList.add('invalid');
74    });
75    
76    input.addEventListener('input', function() {
77        this.classList.remove('invalid');
78    });
79});
80
81// Responsive Table Wrapper
82document.addEventListener('DOMContentLoaded', function() {
83    document.querySelectorAll('table').forEach(table => {
84        if (!table.parentElement.classList.contains('distance-table')) {
85            const wrapper = document.createElement('div');
86            wrapper.className = 'table-responsive';
87            wrapper.style.overflowX = 'auto';
88            table.parentNode.insertBefore(wrapper, table);
89            wrapper.appendChild(table);
90        }
91    });
92});
93
94// Print Page Functionality
95function printPage() {
96    window.print();
97}
98
99// Back to Top Button
100const backToTopButton = document.createElement('button');
101backToTopButton.innerHTML = '↑';
102backToTopButton.className = 'back-to-top';
103backToTopButton.style.cssText = `
104    position: fixed;
105    bottom: 20px;
106    right: 20px;
107    width: 50px;
108    height: 50px;
109    border-radius: 50%;
110    background: #0066CC;
111    color: white;
112    border: none;
113    font-size: 24px;
114    cursor: pointer;
115    display: none;
116    z-index: 999;
117    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
118    transition: all 0.3s ease;
119`;
120
121document.body.appendChild(backToTopButton);
122
123window.addEventListener('scroll', function() {
124    if (window.pageYOffset > 300) {
125        backToTopButton.style.display = 'block';
126    } else {
127        backToTopButton.style.display = 'none';
128    }
129});
130
131backToTopButton.addEventListener('click', function() {
132    window.scrollTo({
133        top: 0,
134        behavior: 'smooth'
135    });
136});
137
138// External Links - Open in New Tab
139document.querySelectorAll('a[href^="http"]').forEach(link => {
140    if (!link.hostname.includes(window.location.hostname)) {
141        link.setAttribute('target', '_blank');
142        link.setAttribute('rel', 'noopener noreferrer');
143    }
144});
145
146// Service Worker Registration (for PWA)
147if ('serviceWorker' in navigator) {
148    window.addEventListener('load', function() {
149        // Uncomment to enable service worker
150        // navigator.serviceWorker.register('/sw.js')
151        //     .then(reg => console.log('Service Worker registered'))
152        //     .catch(err => console.log('Service Worker registration failed'));
153    });
154}
155
156// Performance Monitoring
157window.addEventListener('load', function() {
158    if (window.performance && window.performance.timing) {
159        const perfData = window.performance.timing;
160        const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
161        
162        // Track page load time in GA
163        if (typeof gtag !== 'undefined' && pageLoadTime > 0) {
164            gtag('event', 'timing_complete', {
165                name: 'load',
166                value: pageLoadTime,
167                event_category: 'Performance'
168            });
169        }
170    }
171});
172
173// Detect Ad Blocker
174function detectAdBlocker() {
175    const adTest = document.createElement('div');
176    adTest.innerHTML = '&nbsp;';
177    adTest.className = 'adsbox';
178    document.body.appendChild(adTest);
179    
180    window.setTimeout(function() {
181        if (adTest.offsetHeight === 0) {
182            // Ad blocker detected
183            console.log('Ad blocker detected');
184        }
185        adTest.remove();
186    }, 100);
187}
188
189detectAdBlocker();

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.