PageSourceSearch

https://www.visitvarmland.com/app/themes/a-theme/inc/atheme-mega-menu-scripts.js?ver=1.1.3

js visitvarmland.com collected 2026-09-24 09:49:16 UTC 25,509 bytes, 894 lines download raw bytes

1/**
2 * Scripts with things to do when page loads.
3 * - Display featured image when page loads.
4 * - Add some eventListeners for user interaction with menu items.
5 */
6
7(function ($) {
8	/**
9	 * Display featured image for menu element on li-hover.
10	 * @type {HTMLCollectionOf<Element>}
11	 */
12	initiateMegaMenu();
13	function initiateMegaMenu() {
14		let m = document.getElementById("athemeMegaPrimary");
15		if (!m) {
16			return;
17		}
18		let lis = m.getElementsByClassName("menu-item ");
19		if (lis && lis.length) {
20			// Element for featured image.
21			let wrapper = document.getElementById("athemeMegaImages");
22
23			// Fetured image url.
24			let img = "";
25
26			// So we can check if we have a image to show or not.
27			let check = null;
28
29			// Open or close sub menu when user hover a <li> or on mobile devices click on a menu item/link.
30			let breakPoint = 671; // Breakpoint for rendering a different sub element.
31			let screenWidth = window.innerWidth;
32			let body = window;
33
34			body.onresize = function () {
35				screenWidth = window.innerWidth;
36
37				if (screenWidth < breakPoint) {
38					resetSubMenus();
39				}
40			};
41
42			// Running through all li:s to collect and set data.
43			for (let i = 0; i < lis.length; i++) {
44				// Check for a list item with class "active" = active page. Show this image when menu opens.
45				if (lis[i].classList.contains("active")) {
46					let img = "";
47					img = lis[i].getAttribute("data-img");
48					if (img !== "") {
49						wrapper.style.backgroundImage = "url(" + img + ")";
50					}
51					// We have a hit and we can continue with image information.
52					check = true;
53				}
54
55				// We have no active page. Work with featured image and image data for first link item.
56				if (!check) {
57					img = lis[0].getAttribute("data-img");
58					if (img !== "") {
59						wrapper.style.backgroundImage = "url(" + img + ")";
60					}
61				}
62
63				// Get icon and title for current/selected link.
64				let liContent =
65					lis[i].getElementsByClassName("dropdown-toggle");
66				let title = "";
67				if (liContent.length) {
68					title = liContent[0].innerHTML;
69
70					// Add keyboard navigation to dropdown-toggle links
71					liContent[0].addEventListener("keydown", function (e) {
72						if (e.key === "Enter") {
73							e.preventDefault();
74
75							// Find the submenu
76							let sub = lis[i].querySelector("ul");
77							if (sub) {
78								// Close all other submenus first
79								resetSubMenus();
80
81								// Open this submenu
82								sub.style.display = "block";
83
84								// Adjust menu height for desktop
85								if (screenWidth > breakPoint) {
86									let subId = sub.getAttribute("id");
87									athemeAdjustMenuHeight(
88										lis[i].getAttribute("id"),
89										subId,
90									);
91								}
92
93								// Close submenu when focus leaves the parent li
94								function closeSubOnFocusOut(ev) {
95									if (!lis[i].contains(ev.relatedTarget)) {
96										sub.style.display = "none";
97										lis[i].removeEventListener("focusout", closeSubOnFocusOut);
98									}
99								}
100								lis[i].addEventListener("focusout", closeSubOnFocusOut);
101							}
102						}
103					});
104				}
105
106				// On smaller devices we also want to work with click event.
107				if (screenWidth <= breakPoint) {
108					lis[i].addEventListener("click", function (e) {
109						//e.preventDefault();
110
111						// First close all sub menues.
112						resetSubMenus();
113
114						// Check if we have a list item with class "dropdown". If so, show or hide sub menu.
115						let hasSub = lis[i].classList.contains("dropdown");
116						if (hasSub) {
117							// Show current sub menu.
118							let sub = lis[i].children;
119							if (sub.length) {
120								// If any element in current li is a ul, show or hide it.
121								for (let y = 0; y < sub.length; y++) {
122									if (
123										sub[y].nodeName.toLowerCase() === "ul"
124									) {
125										if (sub[y].style.display === "none") {
126											// Mobile users shall se this element.
127											if (screenWidth <= breakPoint) {
128												let elements = sub[y].innerHTML;
129												athemeShowSubMenu(
130													title,
131													elements,
132												);
133											} else {
134												sub[y].style.display = "block";
135											}
136										} else {
137											sub[y].style.display = "none";
138										}
139									}
140								}
141							}
142						}
143					});
144				}
145
146				// On larger devices, not mobiles. Still works on mobiles if they can trigger a mouse event.
147				lis[i].addEventListener("mouseover", function (e) {
148					if (screenWidth > breakPoint) {
149						// First close all sub menues.
150						for (let z = 0; z < lis.length; z++) {
151							let subLis = lis[z].children;
152							for (let x = 0; x < subLis.length; x++) {
153								if (subLis[x].nodeName.toLowerCase() === "ul") {
154									subLis[x].style.display = "none";
155								}
156							}
157						}
158
159						// Check if we have a list item with class "dropdown". If so, show or hide sub menu on hover.
160						let hasSub = this.classList.contains("dropdown");
161						if (hasSub) {
162							// Show current sub menu.
163							let sub = this.children;
164							if (sub.length) {
165								// If any element in current li is a ul, show or hide it on hover.
166								for (let y = 0; y < sub.length; y++) {
167									if (
168										sub[y].nodeName.toLowerCase() === "ul"
169									) {
170										let subId = sub[y].getAttribute("id");
171
172										if (sub[y].style.display === "none") {
173											sub[y].style.display = "block";
174
175											// Try to adjust menu wrapper min-height.
176											athemeAdjustMenuHeight(
177												this.getAttribute("id"),
178												subId,
179											);
180										} else {
181											sub[y].style.display = "none";
182										}
183									}
184								}
185							}
186						}
187					}
188				});
189
190				// Show featured image on li:hover regardless screensize.
191				lis[i].addEventListener("mouseenter", function () {
192					let img = "";
193					img = this.getAttribute("data-img");
194					if (img !== "") {
195						wrapper.style.backgroundImage = "url(" + img + ")";
196					}
197				});
198			}
199		}
200	}
201
202	/**
203	 * Scripts primary for actions triggered by user.
204	 * - Open and close menues.
205	 * - Change icons in buttons or list items.
206	 * - Show or hide all list items in sub menu and try to adjust element height.
207	 *
208	 */
209
210	/**
211	 * Language switcher keyboard accessibility
212	 */
213	let langSwitcher = document.querySelector(".lang");
214	if (langSwitcher) {
215		// Set ARIA attributes
216		langSwitcher.setAttribute("aria-haspopup", "true");
217		langSwitcher.setAttribute("aria-expanded", "false");
218
219		// Toggle on keyboard activation, but allow Enter on links inside dropdown
220		langSwitcher.addEventListener("keydown", function (e) {
221			if (e.key === "Enter" || e.key === " ") {
222				if (e.target.closest(".lang-dropdown a")) {
223					return;
224				}
225				e.preventDefault();
226				toggleLanguageDropdown();
227			}
228		});
229
230		// Toggle on click, but allow link navigation inside dropdown
231		langSwitcher.addEventListener("click", function (e) {
232			if (e.target.closest(".lang-dropdown a")) {
233				return;
234			}
235			e.preventDefault();
236			toggleLanguageDropdown();
237		});
238
239		// Close on Escape key (handles both lang dropdown and mega menu)
240		document.addEventListener("keydown", function (e) {
241			if (e.key === "Escape") {
242				let dropdown = document.querySelector(".lang-dropdown");
243				if (dropdown && dropdown.classList.contains("show-lang")) {
244					toggleLanguageDropdown();
245					langSwitcher.focus();
246				}
247			}
248		});
249
250		// Close when focus leaves the lang button and its dropdown
251		langSwitcher.addEventListener("focusout", function (e) {
252			if (!langSwitcher.contains(e.relatedTarget)) {
253				let dropdown = document.querySelector(".lang-dropdown");
254				if (dropdown && dropdown.classList.contains("show-lang")) {
255					toggleLanguageDropdown();
256				}
257			}
258		});
259	}
260
261	function toggleLanguageDropdown() {
262		let dropdown = document.querySelector(".lang-dropdown");
263		let langSwitcher = document.querySelector(".lang");
264		if (dropdown) {
265			dropdown.classList.toggle("show-lang");
266			let isExpanded = dropdown.classList.contains("show-lang");
267			langSwitcher.setAttribute("aria-expanded", isExpanded.toString());
268		}
269	}
270
271	/**
272	 * Toggle menu when user click on main menu button.
273	 */
274	let megaMenuToggle = document.getElementById("athemeMegaMenuToggle");
275	if (megaMenuToggle) {
276		megaMenuToggle.addEventListener("click", function (e) {
277			athemeToggleMegaMenu(e.detail === 0);
278
279			//e.preventDefault();
280		});
281	}
282
283	/**
284	 * Close menu when user click on main menu close button (in image field).
285	 */
286	let athemeCloseBtn = document.getElementById("athemeCloseBtn");
287	if (athemeCloseBtn) {
288		athemeCloseBtn.addEventListener("click", function (e) {
289			athemeToggleMegaMenu();
290
291			//e.preventDefault();
292		});
293	}
294
295	/**
296	 * Close mega menu when user click on main menu close button (in Destinations menu field for mobiles).
297	 */
298	let athemeCloseBtnMob = document.getElementById("athemeCloseBtnMob");
299	if (athemeCloseBtnMob) {
300		athemeCloseBtnMob.addEventListener("click", function (e) {
301			athemeToggleMegaMenu();
302
303			//e.preventDefault();
304		});
305	}
306
307	/**
308	 * Close mega menu or dropdown when user presses Escape key
309	 */
310	document.addEventListener("keydown", function (e) {
311		if (e.key === "Escape") {
312			let menu = document.getElementById("athemeMegaMenu");
313			if (menu && menu.classList.contains("atheme-megamenu--open")) {
314				// First check if the destinations panel is open
315				let dMenu = document.getElementById("ammDestinations");
316				if (dMenu && dMenu.classList.contains("atheme-megamenu--open")) {
317					athemeToggleDestinationsMenu();
318					let dBtn = document.getElementById("ammDestinationsBtn");
319					if (dBtn) {
320						dBtn.focus();
321					}
322					return;
323				}
324
325				// Then check if any dropdown submenu is open
326				let m = document.getElementById("athemeMegaPrimary");
327				if (m) {
328					let lis = m.getElementsByClassName("menu-item ");
329					let openDropdownFound = false;
330
331					for (let i = 0; i < lis.length; i++) {
332						let sub = lis[i].querySelector("ul");
333						if (sub && sub.style.display === "block") {
334							// Close this dropdown
335							sub.style.display = "none";
336
337							// Return focus to the dropdown-toggle link
338							let dropdownToggle =
339								lis[i].querySelector(".dropdown-toggle");
340							if (dropdownToggle) {
341								dropdownToggle.focus();
342							}
343
344							openDropdownFound = true;
345							break;
346						}
347					}
348
349					// If no dropdown was open, close the entire megamenu
350					if (!openDropdownFound) {
351						athemeToggleMegaMenu();
352						// Return focus to menu toggle button
353						if (megaMenuToggle) {
354							megaMenuToggle.focus();
355						}
356					}
357				} else {
358					// No primary menu found, just close megamenu
359					athemeToggleMegaMenu();
360					if (megaMenuToggle) {
361						megaMenuToggle.focus();
362					}
363				}
364			}
365		}
366	});
367
368	/**
369	 * Toggle visibility of main mega menu when user click on main menu icon.
370	 */
371	function athemeToggleMegaMenu(openedByKeyboard) {
372		let menu = document.getElementById("athemeMegaMenu");
373		if (menu.classList.contains("atheme-megamenu--open")) {
374			// Closing menu
375			menu.classList.remove("atheme-megamenu--open");
376			resetMegaMenu();
377
378			// Update ARIA and return focus
379			if (megaMenuToggle) {
380				megaMenuToggle.setAttribute("aria-expanded", "false");
381				megaMenuToggle.focus();
382			}
383
384			// Remove focus trap
385			document.removeEventListener("keydown", trapMegaMenuFocus);
386		} else {
387			// Opening menu
388			menu.classList.add("atheme-megamenu--open");
389			athemeBodyPosition();
390
391			// Update ARIA
392			if (megaMenuToggle) {
393				megaMenuToggle.setAttribute("aria-expanded", "true");
394			}
395
396			// Only move focus into the menu when opened via keyboard
397			if (openedByKeyboard) {
398				setTimeout(function () {
399					let allFocusable = menu.querySelectorAll(
400						'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])',
401					);
402					let firstFocusable = Array.from(allFocusable).find(function (el) {
403						return el.offsetParent !== null || el.offsetWidth > 0 || el.offsetHeight > 0;
404					});
405					if (firstFocusable) {
406						firstFocusable.focus();
407					}
408				}, 100);
409			}
410
411			// Add focus trap
412			document.addEventListener("keydown", trapMegaMenuFocus);
413		}
414	}
415
416	/**
417	 * Trap focus within mega menu when open and handle arrow key navigation
418	 */
419	function trapMegaMenuFocus(e) {
420		let menu = document.getElementById("athemeMegaMenu");
421		if (!menu || !menu.classList.contains("atheme-megamenu--open")) {
422			return;
423		}
424
425		let allFocusableElements = menu.querySelectorAll(
426			'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])',
427		);
428
429		// Filter out hidden elements (display: none, visibility: hidden, or not rendered)
430		let focusableElements = Array.from(allFocusableElements).filter(
431			function (el) {
432				// Check if element is visible and takes up space in the layout
433				return el.offsetParent !== null || el.offsetWidth > 0 || el.offsetHeight > 0;
434			},
435		);
436
437		if (focusableElements.length === 0) {
438			return;
439		}
440
441		let firstElement = focusableElements[0];
442		let lastElement = focusableElements[focusableElements.length - 1];
443		let currentIndex = focusableElements.indexOf(document.activeElement);
444
445		// Tab key - trap focus
446		if (e.key === "Tab") {
447			// Shift+Tab on first element -> go to last
448			if (e.shiftKey && document.activeElement === firstElement) {
449				e.preventDefault();
450				lastElement.focus();
451			}
452			// Tab on last element -> go to first
453			else if (!e.shiftKey && document.activeElement === lastElement) {
454				e.preventDefault();
455				firstElement.focus();
456			}
457		}
458
459		// Arrow key navigation
460		else if (e.key === "ArrowDown") {
461			e.preventDefault();
462			if (
463				currentIndex >= 0 &&
464				currentIndex < focusableElements.length - 1
465			) {
466				focusableElements[currentIndex + 1].focus();
467			} else {
468				firstElement.focus();
469			}
470		} else if (e.key === "ArrowUp") {
471			e.preventDefault();
472			if (currentIndex > 0) {
473				focusableElements[currentIndex - 1].focus();
474			} else {
475				lastElement.focus();
476			}
477		}
478
479		// Home/End keys
480		else if (e.key === "Home") {
481			e.preventDefault();
482			firstElement.focus();
483		} else if (e.key === "End") {
484			e.preventDefault();
485			lastElement.focus();
486		}
487	}
488
489	/**
490	 * Restore mega menu to default status.
491	 */
492	function resetMegaMenu() {
493		let destinations = $("#ammDestinations");
494		let primary = $("#ammPrimaryMenu");
495		let secondary = $("#ammSecondaryMenu");
496
497		// Reset main navigation wrappers.
498		destinations.hide();
499		primary.css("display", "flex");
500		secondary.css("display", "flex");
501
502		// Reset subwrappers/menus.
503		athemeHideSubMenu(); // Menus for mobile devices.
504		resetSubMenus(); // Menus for devices larger than mobile.
505
506		// Reset body position.
507		athemeBodyPosition(false);
508
509		initiateMegaMenu();
510	}
511
512	/**
513	 * Reset sub menus for devices larger than mobile.
514	 */
515	function resetSubMenus() {
516		let lis = document
517			.getElementById("athemeMegaPrimary")
518			.getElementsByClassName("menu-item ");
519		if (lis && lis.length) {
520			for (let i = 0; i < lis.length; i++) {
521				let subLis = lis[i].children;
522				for (let x = 0; x < subLis.length; x++) {
523					if (subLis[x].nodeName.toLowerCase() === "ul") {
524						subLis[x].style.display = "none";
525					}
526				}
527			}
528		}
529	}
530
531	/**
532	 * Toggle destinations menu when user click on "Destinations" button.
533	 */
534	$(document).on("click", "#ammDestinationsBtn", function (e) {
535		athemeToggleDestinationsMenu();
536	});
537
538	/**
539	 * Show/hide destinations menu.
540	 */
541	function athemeToggleDestinationsMenu() {
542		// Set wrapper for featured image.
543
544		// Toggle destinations menu.
545		let dMenu = document.getElementById("ammDestinations");
546		let dBtn = document.getElementById("ammDestinationsBtn");
547
548		if (dMenu.classList.contains("atheme-megamenu--open")) {
549			// Remove class, close menu.
550			dMenu.classList.remove("atheme-megamenu--open");
551			dMenu.style.display = "none";
552
553			// Update ARIA
554			if (dBtn) {
555				dBtn.setAttribute("aria-expanded", "false");
556			}
557
558			// Reset mega menu to default state.
559			initiateMegaMenu();
560
561			// Toggle link icon.
562			athemeToggleDestinationsIcon();
563		} else {
564			// Add class, open menu.
565			dMenu.classList.add("atheme-megamenu--open");
566			dMenu.style.display = "flex";
567
568			// Update ARIA
569			if (dBtn) {
570				dBtn.setAttribute("aria-expanded", "true");
571			}
572
573			// Update feature image and hide image description.
574			let bkgImg = document
575				.getElementById("ammDestinations-bkg")
576				.getAttribute("data-img");
577			let imgWrapper = document.getElementById("athemeMegaImages");
578			imgWrapper.style.backgroundImage = "url(" + bkgImg + ")";
579
580			// Toggle link icon.
581			athemeToggleDestinationsIcon();
582		}
583
584		// Toggle primary menu.
585		athemeTogglePrimaryMenu();
586	}
587
588	/**
589	 * When user click on "Destinations" button:
590	 * - Show/hide primary and secondary menu and change button icon (up/down).
591	 * */
592	function athemeTogglePrimaryMenu() {
593		let pMenu = document.getElementById("ammPrimaryMenu");
594		let sMenu = document.getElementById("ammSecondaryMenu");
595
596		if (pMenu.classList.contains("atheme-megamenu--open")) {
597			// Close primary menu.
598			pMenu.classList.remove("atheme-megamenu--open");
599			pMenu.classList.add("atheme-megamenu--closed");
600			pMenu.style.display = "none";
601
602			// Close secondary menu.
603			sMenu.classList.remove("atheme-megamenu--open");
604			sMenu.classList.add("atheme-megamenu--closed");
605			sMenu.style.display = "none";
606		} else {
607			// Open primary menu.
608			pMenu.classList.remove("atheme-megamenu--closed");
609			pMenu.classList.add("atheme-megamenu--open");
610			pMenu.style.display = "flex";
611
612			// Open secondary menu.
613			sMenu.classList.remove("atheme-megamenu--closed");
614			sMenu.classList.add("atheme-megamenu--open");
615			sMenu.style.display = "flex";
616		}
617	}
618
619	/**
620	 * Toggle icon between fa-caret-up and fa-caret-down.
621	 * Also add/remove class .ouline to visually show difference.
622	 */
623	function athemeToggleDestinationsIcon() {
624		let dBtn = document.getElementById("ammDestinationsBtn");
625
626		// Change icon up/down.
627		let i = dBtn.getElementsByTagName("i");
628
629		if (i[1].classList.contains("fa-caret-down")) {
630			i[1].classList.remove("fa-caret-down");
631			i[1].classList.add("fa-caret-up");
632		} else {
633			i[1].classList.remove("fa-caret-up");
634			i[1].classList.add("fa-caret-down");
635		}
636	}
637
638	/**
639	 * Try to adjust menu min-height if sub menu height is higher than its parent menu wrapper height.
640	 * @param id
641	 * @param subId
642	 */
643	function athemeAdjustMenuHeight(id, subId) {
644		// Set CSS breakpoint for screen width (in pixels).
645		let breakPoint = 671;
646
647		// Get parent ul.
648		let parentUlID = document
649			.getElementById(id)
650			.parentElement.getAttribute("id");
651		let parentUl = document.getElementById(parentUlID);
652
653		// Get sub menu ul.
654		let subUl = document.getElementById(subId);
655
656		// Get wrapper for menu.
657		let primaryMenuWrapper = document.getElementById("ammPrimaryMenu");
658
659		// Reset wrapper height before we start to calculate anything.
660		primaryMenuWrapper.style.minHeight = "auto";
661
662		// Get current screen width.
663		let screenWidth = window.innerWidth;
664
665		// Here we go.
666
667		// Try to calculate min-height for menu wrapper when we open sub menu but only for screens > 671px.
668		// We can do better in the future.
669		let elementHeight = primaryMenuWrapper.offsetHeight;
670		let parentUlHeight = parentUl.offsetHeight;
671		let subUlHeight = subUl.offsetHeight;
672
673		if (subUlHeight > parentUlHeight) {
674			let margin = Math.abs(
675				parseFloat(parentUlHeight) - parseFloat(subUlHeight),
676			);
677			let newHeight = "";
678
679			if (margin > 0 && screenWidth > breakPoint) {
680				// Set new height for the wrapper.
681				newHeight = elementHeight + margin;
682
683				// Fix height on wrapper so all links fits in element.
684				if (newHeight > 0) {
685					primaryMenuWrapper.style.minHeight = newHeight + "px";
686				}
687			} else {
688				primaryMenuWrapper.style.minHeight = "unset";
689			}
690		} else {
691			primaryMenuWrapper.style.minHeight = "unset";
692		}
693	}
694
695	/**
696	 * When user click on back button (a), close sub menu wrapper and show secondary menu again.
697	 */
698	$(document).on("click", "#ammSubWrapperBtn", function (e) {
699		athemeHideSubMenu();
700	});
701
702	/**
703	 * Show a mobile sub menu wrapper with icon, title and a list of items. Also close secondary menu.
704	 * @param title
705	 * @param icon
706	 * @param elements
707	 */
708	function athemeShowSubMenu(title, elements) {
709		let wrapper = document.getElementById("ammSubWrapper");
710		let titleWrapper = document.getElementById("ammSubWrapperTitle");
711		let textWrapper = document.getElementById("ammSubWrapperContent");
712		let secondary = document.getElementById("ammSecondaryMenu");
713
714		if (secondary) secondary.style.display = "none";
715		if (wrapper) wrapper.style.display = "block";
716		if (titleWrapper) titleWrapper.innerHTML = title;
717		if (textWrapper) textWrapper.innerHTML = "<ul>" + elements + "</ul>";
718	}
719
720	/**
721	 * Hide a mobile submenu wrapper and reset wrapper content. Also set wrapper with secondary menu as visible.
722	 */
723	function athemeHideSubMenu() {
724		let wrapper = document.getElementById("ammSubWrapper");
725		let titleWrapper = document.getElementById("ammSubWrapperTitle");
726		let textWrapper = document.getElementById("ammSubWrapperContent");
727		let secondary = document.getElementById("ammSecondaryMenu");
728
729		secondary.style.display = "flex";
730		wrapper.style.display = "none";
731		titleWrapper.innerHTML = "";
732		textWrapper.innerHTML = "";
733	}
734
735	/**
736	 * Set body position to static or ''.
737	 * Handy when we want to open a menu or modal and don't want the page behind to scroll.
738	 * Set current Y-pos when user clicks on menu to remember and scroll to when menu close.
739	 * @param fix
740	 */
741	function athemeBodyPosition(fix) {
742		if (typeof fix === "undefined") {
743			fix = false;
744		}
745
746		let scrollY = window.pageYOffset;
747		let tmpY = 0;
748		let body = document.body;
749
750		if (fix) {
751			body.style.position = "static";
752			body.style.overflowY = "hidden";
753
754			aThemeCreateCookie("ammScrollY", scrollY);
755		} else {
756			body.style.position = "unset";
757			body.style.overflowY = "unset";
758
759			tmpY = aThemeReadCookie("ammScrollY");
760			aThemeEraseCookie("ammScrollY");
761			window.scrollTo(0, tmpY);
762		}
763	}
764
765	/**
766	 * Create a cookie named ammScrollY with current Y-pos when user click to open mega menu.
767	 * @param name
768	 * @param value
769	 * @param days
770	 */
771	function aThemeCreateCookie(name, value, days) {
772		let expires = "";
773
774		if (days) {
775			let date = new Date();
776			date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
777			expires = "; expires=" + date.toGMTString();
778		}
779
780		document.cookie =
781			name + "=" + value + expires + "; path=/; SameSite=Lax";
782	}
783
784	/**
785	 * Get Y-pos and return it.
786	 * @param name
787	 * @returns {string|null}
788	 */
789	function aThemeReadCookie(name) {
790		let nameEQ = name + "=";
791		let ca = document.cookie.split(";");
792
793		for (let i = 0; i < ca.length; i++) {
794			let c = ca[i];
795			while (c.charAt(0) === " ") c = c.substring(1, c.length);
796			if (c.indexOf(nameEQ) === 0)
797				return c.substring(nameEQ.length, c.length);
798		}
799
800		return null;
801	}
802
803	/**
804	 * Kill cookie.
805	 * @param name
806	 */
807	function aThemeEraseCookie(name) {
808		aThemeCreateCookie(name, "", -1);
809	}
810
811	/**
812	 * NOT IN USE ATM, KEEP FOR FUTURE USE, DO NOT DELETE!
813	 * Show or hide list items (links) when user click on button "Visa alla aktiviteter".
814	 * We also try to adjust height so all links fits in the element.
815	 * @param id
816	 * @param maxNrOfItems
817	 */
818	function athemeToggleSubItems(id, maxNrOfItems) {
819		let tmpID = id.split("-");
820		tmpID = tmpID[1];
821
822		let ul = document.getElementById(id);
823		let btn = document.getElementById("ammListItemBtn-" + tmpID);
824		let hiddenItems = ul.getElementsByClassName("menu-item closed");
825		let allItems = ul.getElementsByClassName("menu-item");
826		let nrOfHiddenItems = hiddenItems.length;
827		let primaryMenuWrapper = document.getElementById("ammPrimaryMenu");
828
829		// Try to calculate min-height for menu wrapper when we open sub menu but only for screens > 671px.
830		// We can do better in the future.
831		let listFullHeight = ul.offsetHeight;
832		let elementHeight = primaryMenuWrapper.offsetHeight;
833		let screenWidth = window.innerWidth;
834		let margin = Math.abs(
835			parseFloat(elementHeight) - parseFloat(listFullHeight),
836		);
837		let newHeight = "";
838
839		if (margin > 0 && screenWidth > 671) {
840			// Set new height for the wrapper.
841			newHeight = elementHeight + margin;
842
843			// Add a little extra space, just in case.
844			if (allItems.length > 5 && allItems.length < 8) {
845				newHeight = newHeight + 100;
846			}
847			if (allItems.length > 7) {
848				newHeight = newHeight + 250;
849			}
850		}
851
852		// First reset all sub menus so we don't mess upp the presentation.
853		// We have no hidden links. Let's hide them when we passed the number of "maxNrOfItems".
854		for (let i = 0; i < allItems.length; i++) {
855			if (i >= maxNrOfItems) {
856				if (!allItems[i].classList.contains("closed")) {
857					allItems[i].classList.add("closed");
858				}
859			}
860		}
861
862		if (nrOfHiddenItems > 0) {
863			// We have some hidden links, let's show them.
864			for (let i = 0; i < allItems.length; i++) {
865				if (allItems[i].classList.contains("closed")) {
866					allItems[i].classList.remove("closed");
867				}
868			}
869
870			// Change text on button.
871			btn.text = "Återställ";
872
873			// Fix height on wrapper so all links fits in element.
874			primaryMenuWrapper.style.minHeight = "unset";
875			if (newHeight > 0) {
876				primaryMenuWrapper.style.minHeight =
877					parseFloat(newHeight) + "px";
878			}
879		} else {
880			// We have no hidden links. Let's hide them when we passed the number of "maxNrOfItems".
881			for (let i = 0; i < allItems.length; i++) {
882				if (i >= maxNrOfItems) {
883					allItems[i].classList.add("closed");
884				}
885			}
886
887			// Change text on button.
888			btn.text = "Visa alla aktiviteter";
889
890			// Reset height on wrapper.
891			primaryMenuWrapper.style.minHeight = "unset";
892		}
893	}
894})(jQuery);

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.