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.