PageSourceSearch

https://hr-on.com/wp-content/themes/hr-on/js/custom-header.js?v=1781859491

js hr-on.com collected 2026-10-02 03:08:31 UTC 11,708 bytes, 383 lines download raw bytes

1(function(){
2	function qs(s,root){ return (root||document).querySelector(s); }
3	var header = qs('#hron-custom-header');
4	if(!header) return;
5
6	var siteLogo = qs('.hron-site-logo', header);
7	var defaultLogoSrc = 'https://hr-on.com/wp-content/uploads/2025/11/logo-blue.svg';
8	var whiteLogoSrc = 'https://hr-on.com/wp-content/uploads/2025/11/logo-white.svg';
9	var lastIsScrolled = null;
10
11	function updateScrolledState(){
12		var isScrolled = (window.scrollY || window.pageYOffset) > 10;
13		if (isScrolled !== lastIsScrolled) {
14			header.classList.toggle('is-scrolled', isScrolled);
15			if (siteLogo) {
16				siteLogo.setAttribute('src', isScrolled ? whiteLogoSrc : defaultLogoSrc);
17			}
18			lastIsScrolled = isScrolled;
19		}
20	}
21
22	var ticking = false;
23	window.addEventListener('scroll', function(){
24		if (!ticking) {
25			window.requestAnimationFrame(function(){
26				updateScrolledState();
27				ticking = false;
28			});
29			ticking = true;
30		}
31	});
32	
33	// Initialize scroll state on page load
34	updateScrolledState();
35	
36	// Also check when page is fully loaded, in case initial load scroll position wasn't detected
37	window.addEventListener('load', function() {
38		// Use a small delay to ensure everything is settled
39		setTimeout(updateScrolledState, 100);
40	});
41	
42	// Also check when DOM content is fully loaded
43	if (document.readyState === 'loading') {
44		document.addEventListener('DOMContentLoaded', function() {
45			setTimeout(updateScrolledState, 100);
46		});
47	}
48	
49	// Add a more aggressive check - poll for the first few seconds
50	var checkCount = 0;
51	var maxChecks = 20; // Check for 2 seconds (20 * 100ms)
52	var pollInterval = setInterval(function() {
53		checkCount++;
54		updateScrolledState();
55		
56		if (checkCount >= maxChecks) {
57			clearInterval(pollInterval);
58		}
59	}, 100);
60
61	var toggle = qs('.hron-toggle', header);
62	var menu = qs('#hron-custom-header-menu', header);
63
64	if (toggle && menu) {
65		toggle.addEventListener('click', function(){
66			var expanded = this.getAttribute('aria-expanded') === 'true';
67			this.setAttribute('aria-expanded', String(!expanded));
68			header.classList.toggle('is-open', !expanded);
69		});
70
71		// use pointerdown instead of click
72		document.addEventListener('pointerdown', function(e){
73			// only left button (0) and ignore right-clicks (2)
74			if (e.button !== 0) return;
75			if (!header.contains(e.target)) {
76				toggle.setAttribute('aria-expanded', 'false');
77				header.classList.remove('is-open');
78			}
79		});
80	}
81
82	document.addEventListener('keydown', function(e){
83		if (e.key === 'Escape') {
84			if (toggle) toggle.setAttribute('aria-expanded', 'false');
85			header.classList.remove('is-open');
86			var lang = qs('.hron-lang', header);
87			if (lang) {
88				lang.classList.remove('is-open');
89				var btn = qs('.hron-lang-current', lang);
90				if (btn) btn.setAttribute('aria-expanded', 'false');
91			}
92			var login = qs('.hron-login', header);
93			if (login) {
94				login.classList.remove('is-open');
95				var icon = qs('.hron-login-icon', login);
96				if (icon) icon.setAttribute('aria-expanded', 'false');
97			}
98		}
99	});
100
101	function setupDropdown(wrapperSelector, btnSelector, iconSelector) {
102		var wrapper = qs(wrapperSelector, header);
103		if (!wrapper) return;
104		var btn = btnSelector ? qs(btnSelector, wrapper) : null;
105		var icon = iconSelector ? qs(iconSelector, wrapper) : null;
106		var timeout;
107
108		if (btn || icon) {
109			wrapper.addEventListener('mouseenter', function(){
110				clearTimeout(timeout);
111				var other = wrapperSelector === '.hron-lang' ? qs('.hron-login', header) : qs('.hron-lang', header);
112				if (other) {
113					other.classList.remove('is-open');
114					var otherBtn = qs('.hron-lang-current', other);
115					var otherIcon = qs('.hron-login-icon', other);
116					if (otherBtn) otherBtn.setAttribute('aria-expanded', 'false');
117					if (otherIcon) otherIcon.setAttribute('aria-expanded', 'false');
118				}
119				(btn || icon).setAttribute('aria-expanded', 'true');
120				wrapper.classList.add('is-open');
121			});
122
123			wrapper.addEventListener('mouseleave', function(){
124				timeout = setTimeout(function(){
125					(btn || icon).setAttribute('aria-expanded', 'false');
126					wrapper.classList.remove('is-open');
127				}, 300);
128			});
129
130			// also use pointerdown here
131			document.addEventListener('pointerdown', function(e){
132				// Ignore right-clicks (2) and middle clicks (1)
133				if (e.button !== 0) return;
134				if (!wrapper.contains(e.target)) {
135					(btn || icon).setAttribute('aria-expanded', 'false');
136					wrapper.classList.remove('is-open');
137				}
138			});
139		}
140	}
141
142	setupDropdown('.hron-lang', '.hron-lang-current');
143	setupDropdown('.hron-login', null, '.hron-login-icon');
144
145	// Prevent right-click from closing mega menus and handle hover states with JS
146    var megaMenuItems = document.querySelectorAll('.hron-custom-item');
147    var closeTimers = new WeakMap();
148    megaMenuItems.forEach(function(item) {
149		var megaMenu = item.querySelector('.hron-mega');
150		if (!megaMenu) return;
151
152		// Prevent context menu from closing mega menu
153		item.addEventListener('contextmenu', function(e) {
154			e.preventDefault();
155			e.stopPropagation();
156			// Keep the menu open when right-clicking
157			item.classList.add('is-mega-open');
158			return false;
159		});
160
161		// Add mouseenter/mouseleave event handlers
162        item.addEventListener('mouseenter', function() {
163            var t = closeTimers.get(item);
164            if (t) { clearTimeout(t); closeTimers.delete(item); }
165            item.classList.add('is-mega-open');
166        });
167		
168        item.addEventListener('mouseleave', function() {
169            var timer = setTimeout(function(){
170                item.classList.remove('is-mega-open');
171                closeTimers.delete(item);
172            }, 180);
173            closeTimers.set(item, timer);
174        });
175
176        // Keep open when moving over the panel itself
177        megaMenu.addEventListener('mouseenter', function(){
178            var t = closeTimers.get(item);
179            if (t) { clearTimeout(t); closeTimers.delete(item); }
180            item.classList.add('is-mega-open');
181        });
182        megaMenu.addEventListener('mouseleave', function(){
183            var timer = setTimeout(function(){
184                item.classList.remove('is-mega-open');
185                closeTimers.delete(item);
186            }, 180);
187            closeTimers.set(item, timer);
188        });
189	});
190
191	// Prevent right-click event bubbling on mega menu items
192	document.querySelectorAll('.hron-mega, .hron-mega *').forEach(function(element) {
193		element.addEventListener('contextmenu', function(e) {
194			e.preventDefault();
195			e.stopPropagation();
196			
197			// Find the parent menu item and keep it open
198			var menuItem = element.closest('.hron-custom-item');
199			if (menuItem) {
200				menuItem.classList.add('is-mega-open');
201			}
202			
203			return false;
204		});
205	});
206	
207	// Handle submenus separately
208	document.querySelectorAll('.hron-submenu').forEach(function(submenu) {
209		submenu.addEventListener('mouseenter', function() {
210			this.classList.add('is-open');
211		});
212		
213		submenu.addEventListener('mouseleave', function() {
214			this.classList.remove('is-open');
215		});
216		
217		submenu.addEventListener('contextmenu', function(e) {
218			e.preventDefault();
219			e.stopPropagation();
220			this.classList.add('is-open');
221			return false;
222		});
223		
224		// Handle clicks on submenu toggles
225		var toggle = submenu.querySelector('.hron-submenu-toggle');
226		if (toggle) {
227			toggle.addEventListener('contextmenu', function(e) {
228				e.preventDefault();
229				e.stopPropagation();
230				submenu.classList.add('is-open');
231				return false;
232			});
233		}
234	});
235	
236	// Handle add-on links to improve interaction
237	document.querySelectorAll('.hron-mega-list a, .hron-addon-content').forEach(function(link) {
238		link.addEventListener('click', function(e) {
239			// Allow the click to proceed to the link's href
240			// but prevent it from immediately closing the mega menu
241			e.stopPropagation();
242		});
243		
244		// Add hover persistence for better UX
245		link.addEventListener('mouseenter', function() {
246			var menuItem = this.closest('.hron-custom-item');
247			if (menuItem) {
248				menuItem.classList.add('is-mega-open');
249				menuItem.classList.add('hover-persistent');
250			}
251		});
252	});
253
254	function initKunderCarousel() {
255		var reviewCard = qs('.kunder-review-card', header);
256		if (!reviewCard) return;
257
258		var reviewItems = reviewCard.querySelectorAll('.krc-review-item');
259		var dots = reviewCard.querySelectorAll('.krc-dots i');
260		if (reviewItems.length === 0 || dots.length === 0) return;
261
262		var currentIndex = 0;
263		var autoSlideInterval = null;
264		var isHovered = false;
265
266		function setActiveReview(index) {
267			if (index < 0 || index >= reviewItems.length) return;
268
269			reviewItems.forEach(function(item, i) {
270				item.classList.toggle('active', i === index);
271			});
272
273			dots.forEach(function(dot, i) {
274				dot.classList.toggle('active', i === index);
275			});
276
277			var activeItem = reviewItems[index];
278			var reviewType = activeItem.getAttribute('data-review');
279			reviewCard.setAttribute('data-review', reviewType);
280			
281			var bgColor = '#0B5FFF';
282			var borderColor = 'rgba(11,95,255,0.2)';
283			
284			if (reviewType === 'staff') {
285				bgColor = '#FF7000';
286				borderColor = 'rgba(255,112,0,0.3)';
287			} else if (reviewType === 'wellbeing') {
288				bgColor = '#00A37A';
289				borderColor = 'rgba(0,163,122,0.3)';
290			} else if (reviewType === 'boarding') {
291				bgColor = '#FF9F00';
292				borderColor = 'rgba(255,159,0,0.3)';
293			}
294			
295			reviewCard.style.background = bgColor;
296			reviewCard.style.borderColor = borderColor;
297
298			currentIndex = index;
299		}
300
301		function nextReview() {
302			if (isHovered) return;
303			var nextIndex = (currentIndex + 1) % reviewItems.length;
304			setActiveReview(nextIndex);
305		}
306
307		function startAutoSlide() {
308			if (autoSlideInterval) clearInterval(autoSlideInterval);
309			autoSlideInterval = setInterval(nextReview, 5000);
310		}
311
312		function stopAutoSlide() {
313			if (autoSlideInterval) {
314				clearInterval(autoSlideInterval);
315				autoSlideInterval = null;
316			}
317		}
318
319		dots.forEach(function(dot, index) {
320			dot.addEventListener('click', function() {
321				setActiveReview(index);
322				stopAutoSlide();
323				setTimeout(startAutoSlide, 3000);
324			});
325		});
326
327		reviewCard.addEventListener('mouseenter', function() {
328			isHovered = true;
329			stopAutoSlide();
330		});
331
332		reviewCard.addEventListener('mouseleave', function() {
333			isHovered = false;
334			startAutoSlide();
335		});
336
337		startAutoSlide();
338	}
339
340	initKunderCarousel();
341
342	// Office hours status indicator
343	function initOfficeHoursStatus() {
344		var statusIndicator = qs('#hron-status-indicator', header);
345		if (!statusIndicator) return;
346
347		function checkOfficeHours() {
348			// Get current time in Europe/Copenhagen timezone
349			var now = new Date();
350			var copenhagenDate = new Date(now.toLocaleString("en-US", {timeZone: "Europe/Copenhagen"}));
351			var day = copenhagenDate.getDay(); // 0 = Sunday, 1 = Monday, ..., 5 = Friday, 6 = Saturday
352			var hour = copenhagenDate.getHours();
353			var minute = copenhagenDate.getMinutes();
354			var currentTime = hour * 60 + minute; // Convert to minutes for easier comparison
355			
356			// Office hours: Monday (1) to Friday (5), 9 AM (540 minutes) to 3 PM (900 minutes)
357			// 3 PM = 15:00 = 900 minutes, but we check < 900 to exclude 3 PM exactly
358			var isOpen = (day >= 1 && day <= 5) && (currentTime >= 540 && currentTime < 900);
359			
360			if (isOpen) {
361				statusIndicator.classList.add('is-open');
362			} else {
363				statusIndicator.classList.remove('is-open');
364			}
365		}
366
367		// Check immediately
368		checkOfficeHours();
369		
370		// Check every minute to update status in real-time
371		setInterval(checkOfficeHours, 60000);
372		
373		// Also check when page becomes visible (user switches tabs)
374		document.addEventListener('visibilitychange', function() {
375			if (!document.hidden) {
376				checkOfficeHours();
377			}
378		});
379	}
380
381	initOfficeHoursStatus();
382
383})();

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.