1jQuery(document).ready(function ($) { 2 // Add body class 'needed-fix' on specific slugs 3 (function () { 4 var path = window.location.pathname.replace(/\/?$/, "/"); 5 var neededFixSlugs = [ 6 "products", 7 "producten/order-central", 8 "doelgroep/retail-levensmiddelen", 9 "doelgroep/distributie", 10 "doelgroep/fabrikanten", 11 "doelgroep/merken", 12 "doelgroep/e-commerce-marktplaats", 13 "doelgroep/3pl", 14 "producten/integraties", 15 "producten", 16 "/nl/producten/sps-for-3pls/", 17 "/nl/producten/order-central/", 18 "/nl/doelgroep/retail-levensmiddelen/", 19 "/nl/doelgroep/distributie/", 20 "/nl/doelgroep/fabrikanten/", 21 "/nl/doelgroep/merken/", 22 "/nl/doelgroep/e-commerce-marktplaats/", 23 "/nl/doelgroep/3pl/", 24 "/nl/producten/integraties/", 25 "/nl/producten/", 26 "/fr/produits/sps-for-3pls/", 27 "/fr/produits/order-central/", 28 "/fr/produits/", 29 "/fr/audience/retail-epicerie/", 30 "/fr/audience/distribution/", 31 "/fr/audience/marques/", 32 "/fr/audience/fabricants/", 33 "/fr/audience/3pl/", 34 "/fr/audience/ecommerce-marketplace/", 35 "/products/sps-for-3pls/", 36 "/products/supply-chain-performance-suite/", 37 "/products/order-central/", 38 "/products/", 39 "/de/produkte/sps-for-3pls/", 40 "/de/produkte/order-central/", 41 "/de/produkte/integrationen/", 42 "/de/produkte/", 43 "/de/zielgruppe/retail-grocery/", 44 "/de/zielgruppe/brands/", 45 "/de/zielgruppe/ecommerce-marktplatz/", 46 "/de/zielgruppe/3pl/", 47 "/de/", 48 "/eur/", 49 "/eur/products/order-central/", 50 "/eur/products/sps-for-3pls/", 51 "/business-need/edi-mapping/", 52 "/business-need/traceability-and-tracking/", 53 "/lp/product-data-management/", 54 "/lp/mm-supply-chain-performance-suite/", 55 "/lp/get-visibility/", 56 "/lp/food-and-beverage-and-sps-success/", 57 "/edi-guide/edi-solution/", 58 "/resources/benefits-of-edi-for-peter-grimm/", 59 "/de/edi-handbuch/edi-loesung/", 60 "/fr/edi-guide/edi-solution/", 61 "/nl/edi-gids/edi-oplossing/", 62 "/products/integrations/mirakl/", 63 "/products/integrations/data-warehouse-integrations/", 64 "/products/fulfillment/integrated-fulfillment/system-integrations/apparelmagic/", 65 "/products/fulfillment/integrated-fulfillment/system-integrations/microsoft-dynamics-ax/", 66 "/products/fulfillment/integrated-fulfillment/system-integrations/microsoft-dynamics-business-central/", 67 "/products/fulfillment/integrated-fulfillment/system-integrations/microsoft-dynamics-nav/", 68 "/products/fulfillment/integrated-fulfillment/system-integrations/zoho/", 69 "/de/produkte/fulfillment/integrierte-fulfillment/systemintegration/netsuite/", 70 "/eur/products/fulfillment/integrated-fulfillment/system-integrations/netsuite/", 71 ]; 72 if (neededFixSlugs.indexOf(path) !== -1) { 73 document.body.classList.add("needed-fix"); 74 } 75 })(); 76 77 let hideTimeout; 78 let currentSubmenu = null; 79 let closeToken = 0; 80 const SUBMENU_CLOSE_FALLBACK_MS = 700; 81 const SUBMENU_HEIGHT_BUFFER = 8; 82 const SUBMENU_EDGE_MARGIN = 16; 83 let submenuHeightRaf = null; 84 let submenuPositionRaf = null; 85 let isClosingSubmenus = false; 86 let pendingOpen = null; 87 88 const $submenusWrap = $("#submenus"); 89 const $primaryMenuWrap = $("#header .primary-menu"); 90 const $menuHoverBridge = $("#menu-hover-bridge"); 91 const $primaryMenuList = $primaryMenuWrap.find(".main-list"); 92 93 let $menuIndicator = null; 94 let indicatorResizeTimer = null; 95 96 function ensureMenuIndicator() { 97 if (!$primaryMenuList.length) return false;
98 if (!$menuIndicator || !$menuIndicator.length) { 99 $menuIndicator = $primaryMenuList.find(".js-menu-underline"); 100 if (!$menuIndicator.length) { 101 $menuIndicator = $('<span class="menu-underline js-menu-underline" aria-hidden="true"></span>'); 102 $primaryMenuList.append($menuIndicator); 103 } 104 } 105 return true; 106 } 107 108 function updateMenuIndicator($menuItem) { 109 if (!$menuItem || !$menuItem.length) return; 110 if (!ensureMenuIndicator()) return; 111 112 const listEl = $primaryMenuList.get(0); 113 const itemEl = $menuItem.get(0); 114 if (!listEl || !itemEl || !listEl.isConnected || !itemEl.isConnected) return; 115 116 const listRect = listEl.getBoundingClientRect(); 117 const itemRect = itemEl.getBoundingClientRect(); 118 const left = itemRect.left - listRect.left; 119 const width = itemRect.width; 120 121 if (!width || width <= 0) return; 122 123 $menuIndicator.css({ 124 width: width + "px", 125 transform: "translateX(" + left + "px)", 126 }); 127 $menuIndicator.addClass("is-visible"); 128 } 129 130 function hideMenuIndicator() { 131 if (!$menuIndicator || !$menuIndicator.length) return; 132 $menuIndicator.removeClass("is-visible"); 133 } 134 135 function syncIndicatorToCurrentSubmenu() { 136 if (!currentSubmenu) { 137 hideMenuIndicator(); 138 return; 139 } 140 const $item = $primaryMenuWrap.find('.main-list li[data-submenu="' + currentSubmenu + '"]'); 141 if ($item.length) updateMenuIndicator($item); 142 else hideMenuIndicator(); 143 } 144 145 function handleIndicatorResize() { 146 clearTimeout(indicatorResizeTimer); 147 indicatorResizeTimer = setTimeout(function () { 148 const $hovered = $primaryMenuWrap.find(".main-list li:hover"); 149 if ($hovered.length) { 150 updateMenuIndicator($hovered.first()); 151 syncSubmenuHorizontalPosition($hovered.first()); 152 return; 153 } 154 syncIndicatorToCurrentSubmenu(); 155 syncSubmenuMaxHeight(currentSubmenu); 156 syncSubmenuHorizontalPosition(); 157 }, 100); 158 } 159 160 function isDesktopViewport() { 161 return window.innerWidth > 1024; 162 } 163 164 function isAdminBarVisible() { 165 const adminBar = document.getElementById("wpadminbar"); 166 if (!adminBar) return false; 167 168 const style = window.getComputedStyle(adminBar); 169 if (style.display === "none" || style.visibility === "hidden") return false; 170 171 return adminBar.offsetHeight > 0; 172 } 173 174 function syncSubmenuHorizontalPosition($menuItem) { 175 const submenusEl = $submenusWrap.get(0); 176 const pageContainer = document.getElementById("page-container"); 177 if (!submenusEl || !pageContainer) return; 178 179 if (!$menuItem || !$menuItem.length) { 180 if (!currentSubmenu) return; 181 $menuItem = $primaryMenuWrap.find('.main-list li[data-submenu="' + currentSubmenu + '"]'); 182 if (!$menuItem.length) return; 183 } 184 185 const applyPosition = () => { 186 const itemEl = $menuItem.get(0); 187 if (!itemEl || !itemEl.isConnected) return; 188 189 const itemRect = itemEl.getBoundingClientRect(); 190 const containerRect = pageContainer.getBoundingClientRect(); 191 if (!itemRect.width) return; 192 193 const itemCenterX = itemRect.left + itemRect.width / 2; 194 const desiredLeft = itemCenterX - containerRect.left; 195 const submenusWidth = submenusEl.offsetWidth; 196 const halfWidth = submenusWidth / 2; 197 198 let left = desiredLeft; 199 if (halfWidth > 0) { 200 const minLeft = halfWidth + SUBMENU_EDGE_MARGIN; 201 const maxLeft = containerRect.width - halfWidth - SUBMENU_EDGE_MARGIN; 202 if (maxLeft >= minLeft) { 203 left = Math.max(minLeft, Math.min(maxLeft, desiredLeft)); 204 } 205 } 206 207 submenusEl.style.left = Math.round(left) + "px"; 208 }; 209 210 if (submenuPositionRaf) cancelAnimationFrame(submenuPositionRaf); 211 submenuPositionRaf = requestAnimationFrame(applyPosition); 212 } 213 214 function computeSubmenuMaxHeight(submenuId) { 215 if (!submenuId) return 0; 216 const $targets = $('.submenu[data-id="' + submenuId + '"], .sibmenu[data-id="' + submenuId + '"]'); 217 if (!$targets.length) return 0; 218 219 let maxHeight = 0; 220 $targets.each(function () { 221 const height = $(this).outerHeight(); 222 if (height > maxHeight) maxHeight = height; 223 }); 224 225 if (!maxHeight) return 0; 226 227 const wrapEl = $submenusWrap.get(0); 228 const wrapStyles = wrapEl ? window.getComputedStyle(wrapEl) : null; 229 const wrapPaddingTop = wrapStyles ? parseFloat(wrapStyles.paddingTop) || 0 : 0; 230 const wrapPaddingBottom = wrapStyles ? parseFloat(wrapStyles.paddingBottom) || 0 : 0; 231 232 return Math.ceil(maxHeight + wrapPaddingTop + wrapPaddingBottom + SUBMENU_HEIGHT_BUFFER); 233 } 234 235 function syncSubmenuMaxHeight(submenuId, immediate) { 236 if (!$submenusWrap.length) return; 237 if (!submenuId) { 238 $submenusWrap.css("--submenu-max-height", "0px"); 239 return; 240 } 241 242 const applyHeight = () => { 243 const computedHeight = computeSubmenuMaxHeight(submenuId); 244 if (computedHeight > 0) { 245 $submenusWrap.css("--submenu-max-height", computedHeight + "px"); 246 } else { 247 $submenusWrap.css("--submenu-max-height", "0px"); 248 } 249 syncSubmenuHorizontalPosition(); 250 }; 251 252 if (immediate) { 253 applyHeight(); 254 return; 255 } 256 257 if (submenuHeightRaf) cancelAnimationFrame(submenuHeightRaf); 258 submenuHeightRaf = requestAnimationFrame(applyHeight); 259 } 260 261 $(window).on("resize", handleIndicatorResize); 262 263 const MAIN_LIST_ARROW_CLASS = "js-main-list-arrow"; 264 const MAIN_LIST_ARROW_STYLE_ID = "js-main-list-arrow-styles"; 265 266 function initMainListArrows() { 267 if (!$primaryMenuList.length) return; 268 const $itemsWithSubmenu = $primaryMenuWrap.find(".main-list li[data-submenu]"); 269 if (!$itemsWithSubmenu.length) return; 270 271 if (!document.getElementById(MAIN_LIST_ARROW_STYLE_ID)) { 272 const style = document.createElement("style"); 273 style.id = MAIN_LIST_ARROW_STYLE_ID; 274 style.textContent = 275 "#header .primary-menu .main-list li ." + 276 MAIN_LIST_ARROW_CLASS + 277 " { display: inline-flex; align-items: center; justify-content: center; transition: transform 0.35s ease; } " + 278 "#header .primary-menu .main-list li.active ." + 279 MAIN_LIST_ARROW_CLASS + 280 " { transform: rotate(180deg); } " + 281 "@media (min-width: 1025px) { #header .primary-menu .main-list li ." + 282 MAIN_LIST_ARROW_CLASS + 283 " { display: none !important; } }"; 284 document.head.appendChild(style); 285 } 286 287 const arrowSvg = 288 '<span class="' + 289 MAIN_LIST_ARROW_CLASS + 290 '" aria-hidden="true" role="presentation">' + 291 '<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L5 5L9 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
291' + 292 "</span>"; 293 294 $itemsWithSubmenu.each(function () { 295 if ($(this).find("." + MAIN_LIST_ARROW_CLASS).length) return; 296 $(this).append(arrowSvg); 297 }); 298 } 299 300 initMainListArrows(); 301 302 function queueSubmenuOpen($menuItem, submenuId) { 303 pendingOpen = { $menuItem, submenuId }; 304 } 305 306 function openPendingSubmenu() { 307 if (!pendingOpen) return; 308 const { $menuItem, submenuId } = pendingOpen; 309 pendingOpen = null; 310 311 if ($menuItem && $menuItem.length && $menuItem.is(":hover")) { 312 activateSubmenu($menuItem, submenuId); 313 } 314 } 315 316 function hideSubmenusInstantly() { 317 $(".submenu, .sibmenu").css("display", "none"); 318 } 319 320 function clearActiveSubmenusIfClosed(token) { 321 if (token !== closeToken) return; 322 if ($submenusWrap.hasClass("active")) return; // reopen before transition finished 323 $(".submenu, .sibmenu").removeClass("active"); 324 currentSubmenu = null; 325 hideMenuIndicator(); 326 syncSubmenuMaxHeight(null); 327 } 328 329 function beginCloseSubmenus(options) { 330 if (isClosingSubmenus) return; 331 const token = ++closeToken; 332 const immediateClose = !!(options && options.immediate); 333 let previousTransition = ""; 334 335 isClosingSubmenus = true; 336 337 const el = document.getElementById("submenus"); 338 if (immediateClose && el) { 339 previousTransition = el.style.transition; 340 el.style.transition = "none"; 341 void el.offsetHeight; 342 } 343 344 $submenusWrap.removeClass("active"); 345 if (immediateClose) { 346 $(".submenu, .sibmenu").removeClass("active"); 347 hideSubmenusInstantly(); 348 } 349 $(".primary-menu .main-list li").removeClass("active"); 350 351 if (!el || immediateClose) { 352 if (el && immediateClose) { 353 void el.offsetHeight; 354 el.style.transition = previousTransition; 355 } 356 clearActiveSubmenusIfClosed(token); 357 isClosingSubmenus = false; 358 openPendingSubmenu(); 359 return; 360 } 361 362 let finished = false; 363 const finish = () => { 364 if (finished) return; 365 finished = true; 366 el.removeEventListener("transitionend", onTransitionEnd); 367 clearTimeout(fallback); 368 clearActiveSubmenusIfClosed(token); 369 isClosingSubmenus = false; 370 openPendingSubmenu(); 371 }; 372 373 const onTransitionEnd = (e) => { 374 if (e && e.target !== el) return; 375 finish(); 376 }; 377 378 el.addEventListener("transitionend", onTransitionEnd); 379 const fallback = setTimeout(finish, SUBMENU_CLOSE_FALLBACK_MS); 380 } 381 382 function scheduleClose(delayMs) { 383 clearTimeout(hideTimeout); 384 hideTimeout = setTimeout(function () { 385 if ($primaryMenuWrap.is(":hover")) return; 386 if ($submenusWrap.is(":hover")) return; 387 if ($menuHoverBridge.length && $menuHoverBridge.is(":hover")) return; 388 pendingOpen = null; 389 beginCloseSubmenus(); 390 }, delayMs || 250); 391 } 392 393 function activateSubmenu($menuItem, submenuId) { 394 $(".primary-menu .main-list li").removeClass("active"); 395 $menuItem.addClass("active"); 396 397 if (currentSubmenu && currentSubmenu !== submenuId) { 398 $('.submenu[data-id="' + currentSubmenu + '"], .sibmenu[data-id="' + currentSubmenu + '"]').removeClass("active"); 399 } 400 401 const $targets = $('.submenu[data-id="' + submenuId + '"], .sibmenu[data-id="' + submenuId + '"]'); 402 $targets.css("display", ""); 403 syncSubmenuMaxHeight(submenuId, true); 404 $submenusWrap.addClass("active"); 405 $targets.addClass("active"); 406 currentSubmenu = submenuId; 407 updateMenuIndicator($menuItem); 408 syncSubmenuMaxHeight(submenuId); 409 syncSubmenuHorizontalPosition($menuItem); 410 } 411 412 $(".primary-menu .main-list li").hover( 413 function () { 414 const submenuId = $(this).data("submenu"); 415 const $menuItem = $(this); 416 417 clearTimeout(hideTimeout); 418 updateMenuIndicator($menuItem); 419 syncSubmenuHorizontalPosition($menuItem); 420 421 const hasOtherActive = 422 currentSubmenu && 423 currentSubmenu !== submenuId && 424 ($submenusWrap.hasClass("active") || $(".submenu.active, .sibmenu.active").length > 0); 425 426 if (hasOtherActive || isClosingSubmenus) { 427 queueSubmenuOpen($menuItem, submenuId); 428 beginCloseSubmenus({ immediate: true }); 429 return; 430 } 431 432 activateSubmenu($menuItem, submenuId); 433 }, 434 function () { 435 const submenuId = $(this).data("submenu"); 436 const $menuItem = $(this); 437 438 $menuItem.removeClass("active"); 439 syncIndicatorToCurrentSubmenu(); 440 scheduleClose(250); 441 }, 442 ); 443 444 const $activePrimaryItem = $primaryMenuWrap.find(".main-list li.active-page"); 445 if ($activePrimaryItem.length) { 446 currentSubmenu = $activePrimaryItem.attr("data-submenu"); 447 syncIndicatorToCurrentSubmenu(); 448 } 449 450 $submenusWrap.hover( 451 function () { 452 clearTimeout(hideTimeout); 453 }, 454 function () { 455 scheduleClose(200); 456 }, 457 ); 458 459 $primaryMenuWrap.hover( 460 function () { 461 clearTimeout(hideTimeout); 462 }, 463 function () { 464 scheduleClose(250); 465 }, 466 ); 467 468 $menuHoverBridge.hover( 469 function () { 470 clearTimeout(hideTimeout); 471 }, 472 function () { 473 scheduleClose(250); 474 }, 475 ); 476 477 $(".tabs-wrap .tab").on("mouseenter", function () { 478 const tabValue = $(this).data("tab"); 479 const parentSubmenu = $(this).closest(".submenu"); 480 481 if (!parentSubmenu.length) { 482 return; 483 } 484 485 parentSubmenu.find(".tabs-wrap .tab").removeClass("active"); 486 487 $(this).addClass("active"); 488 489 parentSubmenu.find(".multi-cols").removeClass("active"); 490 491 parentSubmenu.find('.multi-cols[data-menu="' + tabValue + '"]').addClass("active"); 492 syncSubmenuMaxHeight(currentSubmenu, true); 493 syncSubmenuHorizontalPosition(); 494 }); 495 496 const MOBILE_BREAKPOINT = 1024; 497 const $mobileMenu = $("#mobile-menu"); 498 const $root = $("html"); 499 const MOBILE_NAV_WRAPPER_ID = "js-mobile-primary-nav"; 500 const MOBILE_MENU_OPEN_CLASS = "is-open"; 501 const MM_WRAPPER_CLASS = "js-mm"; 502 const MM_SUBMENU_OPEN_CLASS = "js-mm--submenu-open"; 503 const MM_SUBMENU_CONTENT_CLASS = "js-mm__submenu-content"; 504 const MM_SUBMENU_TITLE_CLASS = "js-mm__submenu-title"; 505 const MM_SECTION_OPEN_CLASS = "is-open"; 506 507 let originalNavEl = null; 508 let placeholderNode = null; 509 let mobileNavEl = null; 510 let isMobileApplied = false;
511 let isBurgerBound = false; 512 let langSwitcherOriginalParent = null; 513 let langSwitcherOriginalNextSibling = null; 514 515 function findPrimaryNav() { 516 return document.querySelector("nav.primary-list") || document.querySelector("nav.primary-menu"); 517 } 518 519 function cloneAttributes(fromEl, toEl) { 520 if (!fromEl || !toEl || !fromEl.attributes) return; 521 for (let i = 0; i < fromEl.attributes.length; i++) { 522 const attr = fromEl.attributes[i]; 523 toEl.setAttribute(attr.name, attr.value); 524 } 525 } 526 527 function replaceTagPreserveAttributes(el, newTagName) { 528 if (!el || !el.parentNode) return null; 529 const replacement = document.createElement(newTagName); 530 cloneAttributes(el, replacement); 531 while (el.firstChild) replacement.appendChild(el.firstChild); 532 el.parentNode.replaceChild(replacement, el); 533 return replacement; 534 } 535 536 function transformUlLiToDiv(root) { 537 if (!root || !root.querySelectorAll) return; 538 const nodes = Array.from(root.querySelectorAll("ul, li")); 539 nodes.reverse().forEach((node) => replaceTagPreserveAttributes(node, "div")); 540 } 541 542 function safeCssEscape(value) { 543 if (window.CSS && typeof window.CSS.escape === "function") return window.CSS.escape(value); 544 return String(value).replace(/["\\]/g, "\\$&"); 545 } 546 547 function getMenuItemLabel(el) { 548 if (!el) return ""; 549 const clone = el.cloneNode(true); 550 const arrow = clone.querySelector(".submenu-arrow"); 551 if (arrow) arrow.remove(); 552 return (clone.textContent || "").trim(); 553 } 554 555 function buildLinkListFromMultiCols(rootEl) { 556 const wrapper = document.createElement("div"); 557 wrapper.className = "js-mm-links"; 558 559 const links = Array.from(rootEl.querySelectorAll(".col a:not(.no-responsive)")).filter((a) => !a.closest(".announcement")); 560 links.forEach((a) => { 561 const href = a.getAttribute("href") || "#"; 562 const label = 563 (a.querySelector(".text-wrap .page-name") && a.querySelector(".text-wrap .page-name").textContent) || (a.textContent || "").trim(); 564 565 if (!label) return; 566 567 const linkEl = document.createElement("a"); 568 linkEl.className = "js-mm-link"; 569 const col = a.closest(".col"); 570 if (a.classList.contains("hidden-nav-item") || (col && col.classList.contains("hidden-nav-item"))) { 571 linkEl.classList.add("hidden-nav-item"); 572 } 573 linkEl.setAttribute("href", href); 574 linkEl.textContent = label.trim(); 575 wrapper.appendChild(linkEl); 576 }); 577 578 return wrapper; 579 } 580 581 function buildAccordionFromTabbedSubmenu(submenuEl) { 582 const accordion = document.createElement("div"); 583 accordion.className = "js-mm-accordion"; 584 585 function findBestHrefForTab(tabValue) { 586 const cols = submenuEl.querySelector('.multi-cols[data-menu="' + safeCssEscape(tabValue) + '"]'); 587 if (!cols) return "#"; 588 589 const cta = cols.querySelector("a.global-btn[href]"); 590 const ctaHref = cta && cta.getAttribute("href"); 591 if (ctaHref && ctaHref !== "#") return ctaHref; 592 593 const anyLink = Array.from(cols.querySelectorAll("a[href]")).find((a) => { 594 const href = a.getAttribute("href"); 595 return href && href !== "#"; 596 }); 597 return (anyLink && anyLink.getAttribute("href")) || "#"; 598 } 599 600 const tabs = Array.from(submenuEl.querySelectorAll(".tabs-wrap .tab"));
601 tabs.forEach((tab, idx) => { 602 const tabValue = tab.getAttribute("data-tab"); 603 if (!tabValue) return; 604 605 const title = (tab.querySelector(".page-name") && tab.querySelector(".page-name").textContent) || tabValue; 606 607 const section = document.createElement("div"); 608 section.className = "js-mm-section"; 609 610 if (tabValue === "strategic-partners") { 611 const href = findBestHrefForTab(tabValue); 612 const link = document.createElement("a"); 613 link.className = "js-mm-section__link"; 614 link.setAttribute("href", href); 615 link.textContent = title.trim(); 616 section.appendChild(link); 617 accordion.appendChild(section); 618 return; 619 } 620 621 const head = document.createElement("button"); 622 head.type = "button"; 623 head.className = "js-mm-section__head"; 624 head.setAttribute("data-tab", tabValue); 625 head.innerHTML = ` 626 <span class="js-mm-section__title"></span> 627 <span class="js-mm-section__chev"> 628 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="9" viewBox="0 0 18 9" fill="none"> 629 <path d="M0.744629 1.01074L8.79096 6.93962L16.8373 1.01074" stroke="black" stroke-width="2.51091" /> 630 </svg> 631 </span> 632 `; 633 head.querySelector(".js-mm-section__title").textContent = title.trim(); 634 635 const body = document.createElement("div"); 636 body.className = "js-mm-section__body"; 637 638 const cols = submenuEl.querySelector('.multi-cols[data-menu="' + safeCssEscape(tabValue) + '"]'); 639 if (cols) body.appendChild(buildLinkListFromMultiCols(cols)); 640 641 section.appendChild(head); 642 section.appendChild(body); 643 accordion.appendChild(section); 644 }); 645 646 return accordion; 647 } 648 649 function buildMobileSubmenuContent(submenuId) { 650 const selector = '#submenus .submenu[data-id="' + safeCssEscape(submenuId) + '"]'; 651 const sourceSubmenu = document.querySelector(selector); 652 if (!sourceSubmenu) return null; 653 654 const clone = sourceSubmenu.cloneNode(true); 655 clone.classList.remove("active"); 656 657 if (clone.querySelector(".tabs-wrap .tab")) { 658 return buildAccordionFromTabbedSubmenu(clone); 659 } 660 const cols = clone.querySelector(".multi-cols") || clone; 661 return buildLinkListFromMultiCols(cols); 662 } 663 664 function closeMobileMenu() { 665 $mobileMenu.removeClass(MOBILE_MENU_OPEN_CLASS); 666 const $mm = $mobileMenu.find("#" + MOBILE_NAV_WRAPPER_ID); 667 $mm.removeClass(MM_SUBMENU_OPEN_CLASS); 668 $mm.find("." + MM_SUBMENU_CONTENT_CLASS).empty(); 669 $mm.find("." + MM_SUBMENU_TITLE_CLASS).text(""); 670 $root.removeClass("mobile-menu-open"); 671 $("body").removeClass("mobile-menu-open"); 672 } 673 674 function openMobileMenu() { 675 $mobileMenu.addClass(MOBILE_MENU_OPEN_CLASS); 676 $root.addClass("mobile-menu-open"); 677 $("body").addClass("mobile-menu-open"); 678 } 679 680 function ensureMobileCloseIcon() { 681 const el = document.querySelector("#header .burger-menu"); 682 if (!el) return; 683 if (el.querySelector(".js-burger-close-icon")) return; 684 685 const wrap = document.createElement("div"); 686 wrap.className = "js-burger-close-icon"; 687 wrap.setAttribute("aria-hidden", "true"); 688 wrap.innerHTML = ` 689 <svg xmlns="http://www.w3.org/2000/svg" width="37" height="37" viewB
689ox="0 0 37 37" fill="none"> 690 <circle cx="18.5" cy="18.5" r="18.5" fill="#EBEBEC"/> 691 <rect x="26.0283" y="10.3983" width="0.812805" height="22.1026" transform="rotate(45 26.0283 10.3983)" fill="black" stroke="black" stroke-width="0.411111"/> 692 <rect x="-1.22521e-08" y="-0.290699" width="0.812805" height="22.1026" transform="matrix(-0.707107 0.707107 0.707107 0.707107 11.1785 10.6038)" fill="black" stroke="black" stroke-width="0.411111"/> 693 </svg> 694 `; 695 el.appendChild(wrap); 696 } 697 698 function bindBurgerOnce() { 699 if (isBurgerBound) return; 700 isBurgerBound = true; 701 702 ensureMobileCloseIcon(); 703 704 $(document).on("click", "#header .burger-menu", function () { 705 if ($mobileMenu.hasClass(MOBILE_MENU_OPEN_CLASS)) closeMobileMenu(); 706 else openMobileMenu(); 707 }); 708 709 $mobileMenu.on("click", ".js-mm__close", function () { 710 closeMobileMenu(); 711 }); 712 } 713 714 function applyMobile() { 715 if (isMobileApplied) return; 716 if (!$mobileMenu.length) return; 717 718 const nav = findPrimaryNav(); 719 if (!nav || !nav.parentNode) return; 720 721 originalNavEl = nav; 722 723 placeholderNode = document.createComment("primary-nav-placeholder"); 724 originalNavEl.parentNode.insertBefore(placeholderNode, originalNavEl); 725 726 $(originalNavEl).detach(); 727 728 mobileNavEl = originalNavEl.cloneNode(true); 729 transformUlLiToDiv(mobileNavEl); 730 731 $mobileMenu.find("#" + MOBILE_NAV_WRAPPER_ID).remove(); 732 const mm = document.createElement("div"); 733 mm.id = MOBILE_NAV_WRAPPER_ID; 734 mm.className = MM_WRAPPER_CLASS; 735 mm.innerHTML = ` 736 <div class="js-mm__panel js-mm__panel--root"> 737 <div class="js-mm__top"> 738 <div class="js-mm__brand"></div> 739 <div class="js-mm__lang"></div> 740 <button type="button" class="js-mm__close" aria-label="Close">Ã</button> 741 </div> 742 <div class="js-mm__content js-mm__content--root"></div> 743 </div> 744 <div class="js-mm__panel js-mm__panel--submenu"> 745 <div class="js-mm__top"> 746 <button type="button" class="js-mm__back" aria-label="Back"> 747 <svg xmlns="http://www.w3.org/2000/svg" width="9" height="18" viewBox="0 0 9 18" fill="none"> 748 <path d="M7.48828 16.8374L1.5594 8.79107L7.48828 0.744736" stroke="#00AAE5" stroke-width="2.51091"/> 749 </svg>Back 750 </button> 751 752 </div> 753 <div class="js-mm__content js-mm__content--submenu"> 754 <div class="${MM_SUBMENU_TITLE_CLASS}"></div> 755 <div class="${MM_SUBMENU_CONTENT_CLASS}"></div> 756 </div> 757 </div> 758 <div class="js-mm__bottom"></div> 759 `; 760 761 const brand = mm.querySelector(".js-mm__brand"); 762 const logo = document.querySelector("#header .logo-wrap"); 763 if (logo) brand.appendChild(logo.cloneNode(true)); 764 765 const langContainer = mm.querySelector(".js-mm__lang"); 766 const langSource = document.querySelector("#languages-select") || document.querySelector("#header .languages-select"); 767 if (langContainer && langSource && langSource.parentNode) { 768 langSwitcherOriginalParent = langSource.parentNode; 769 langSwitcherOriginalNextSibling = langSource.nextSibling; 770 langContainer.appendChild(langSource); 771 } 772 773 const rootContent = mm.querySelector(".js-mm__content--root"); 774 rootContent.appendChild(mobileNavEl); 775 776 const mobileMainList = mobileNavEl.querySelector(".main-list"); 777 if (mobileMainList) { 778 const headerSearchInput = 779 document.querySelector("#header .search-wrap input[type='search']") || document.querySelector("#header input[name='s']"); 780 const searchLabel = (headerSearchInput && (headerSearchInput.getAttribute("placeholder") || headerSearchInput.placeholder)) || "Search"; 781 const searchHref = window.location.origin + "/search/"; 782 const searchItem = document.createElement("div"); 783 searchItem.setAttribute("data-submenu", "static"); 784 searchItem.setAttribute("data-href", searchHref); 785 searchItem.textContent = searchLabel; 786 mobileMainList.appendChild(searchItem); 787 } 788 789 const secondaryMenu = document.querySelector("#header nav.secondary-menu"); 790 let loginHref = "#"; 791 let contactHref = "#"; 792 793 if (secondaryMenu) { 794 const loginA = 795 secondaryMenu.querySelector('a[aria-label="Login"]') || 796 Array.from(secondaryMenu.querySelectorAll("a")).find((a) => (a.textContent || "").trim().toLowerCase() === "login"); 797 const contactA = 798 secondaryMenu.querySelector("a.contact-sales") || 799 secondaryMenu.querySelector('a[aria-label="Contact Sales"]') || 800 Array.from(secondaryMenu.querySelectorAll("a")).find((a) => (a.textContent || "").trim().toLowerCase() === "contact sales"); 801 802 if (loginA) loginHref = loginA.getAttribute("href") || loginHref; 803 if (contactA) contactHref = contactA.getAttribute("href") || contactHref; 804 } 805 806 const bottom = mm.querySelector(".js-mm__bottom"); 807 if (bottom) { 808 const contact = document.createElement("a"); 809 contact.className = "contact-sales js-mm__bottom-contact"; 810 contact.setAttribute("href", contactHref); 811 contact.textContent = "Contact Sales"; 812 813 const login = document.createElement("a"); 814 login.className = "js-mm__bottom-login"; 815 login.setAttribute("href", loginHref); 816 login.textContent = "Login"; 817 818 bottom.appendChild(contact); 819 bottom.appendChild(login); 820 } 821 $mobileMenu.append(mm); 822 823 $mobileMenu.off("click.mm"); // avoid duplicates 824 $mobileMenu.on("click.mm", "#" + MOBILE_NAV_WRAPPER_ID + " [data-submenu]", function (e) { 825 if ($(e.target).closest("a, button, input, textarea, select, label").length) return; 826 const submenuId = $(this).attr("data-submenu"); 827 if (!submenuId) return; 828 829 if (submenuId === "static") { 830 const href = $(this).attr("data-href"); 831 if (href) window.location.href = href; 832 return; 833 } 834 835 const title = getMenuItemLabel(this); 836 const content = buildMobileSubmenuContent(submenuId); 837 const $mm = $mobileMenu.find("#" + MOBILE_NAV_WRAPPER_ID); 838 $mm.find("." + MM_SUBMENU_CONTENT_CLASS) 839 .empty() 840 .append(content || ""); 841 $mm.find("." + MM_SUBMENU_CONTENT_CLASS) 842 .find(".js-mm-section") 843 .first() 844 .addClass(MM_SECTION_OPEN_CLASS); 845 $mm.find("." + MM_SUBMENU_TITLE_CLASS).text(title); 846 $mm.addClass(MM_SUBMENU_OPEN_CLASS); 847 }); 848 849 $mobileMenu.on("click.mm", "#" + MOBILE_NAV_WRAPPER_ID + " .js-mm__back", function () { 850 const $mm = $mobileMenu.find("#" + MOBILE_NAV_WRAPPER_ID); 851 $mm.removeClass(MM_SUBMENU_OPEN_CLASS); 852 $mm.find("." + MM_SUBMENU_CONTENT_CLASS).empty(); 853 $mm.find("." + MM_SUBMENU_TITLE_CLASS).text(""); 854 }); 855 856 $mobileMenu.on("click.mm", "#" + MOBILE_NAV_WRAPPER_ID + " .js-mm-section__head", function () {
857 const $section = $(this).closest(".js-mm-section"); 858 $section.toggleClass(MM_SECTION_OPEN_CLASS); 859 }); 860 861 bindBurgerOnce(); 862 isMobileApplied = true; 863 } 864 865 function applyDesktop() { 866 if (!isMobileApplied) return; 867 868 closeMobileMenu(); 869 870 const $mm = $mobileMenu.find("#" + MOBILE_NAV_WRAPPER_ID); 871 const langContainer = $mm.find(".js-mm__lang")[0]; 872 if (langContainer && langContainer.firstChild && langSwitcherOriginalParent) { 873 const langNode = langContainer.firstChild; 874 langSwitcherOriginalParent.insertBefore(langNode, langSwitcherOriginalNextSibling); 875 langSwitcherOriginalParent = null; 876 langSwitcherOriginalNextSibling = null; 877 } 878 879 $mm.remove(); 880 mobileNavEl = null; 881 882 if (originalNavEl && placeholderNode && placeholderNode.parentNode) { 883 placeholderNode.parentNode.insertBefore(originalNavEl, placeholderNode); 884 placeholderNode.parentNode.removeChild(placeholderNode); 885 } 886 887 placeholderNode = null; 888 isMobileApplied = false; 889 } 890 891 function syncHeaderNavLocation() { 892 const w = window.innerWidth || document.documentElement.clientWidth || 0; 893 if (w <= MOBILE_BREAKPOINT) applyMobile(); 894 else applyDesktop(); 895 } 896 897 let resizeRaf = null; 898 syncHeaderNavLocation(); 899 $(window).on("resize orientationchange", function () { 900 if (resizeRaf) cancelAnimationFrame(resizeRaf); 901 resizeRaf = requestAnimationFrame(syncHeaderNavLocation); 902 }); 903 904 function equalizeSolutionsForHeight() { 905 const DESKTOP_BREAKPOINT = 991; 906 const $solutionsSubmenu = $('.submenu[data-id="solutions-for"]'); 907 const $multiCols = $solutionsSubmenu.find(".multi-cols"); 908 909 if (!$multiCols.length) return; 910 911 if (window.innerWidth <= DESKTOP_BREAKPOINT) { 912 // Reset heights on mobile 913 $multiCols.each(function () { 914 this.style.removeProperty("min-height"); 915 }); 916 return; 917 } 918 919 $multiCols.each(function () { 920 this.style.removeProperty("min-height"); 921 }); 922 923 $solutionsSubmenu.css({ 924 opacity: "1", 925 visibility: "visible", 926 pointerEvents: "none", 927 }); 928 929 $multiCols.each(function () { 930 const isGrid = 931 this.classList.contains("grid-col-three-row-five") || 932 this.classList.contains("grid-col-three-row-four"); 933 this.style.setProperty("display", isGrid ? "grid" : "flex"); 934 this.style.setProperty("visibility", "visible"); 935 this.style.setProperty("position", "absolute"); 936 this.style.setProperty("opacity", "0"); 937 this.style.setProperty("width", "100%"); 938 this.style.setProperty("left", "0"); 939 }); 940 941 // Find max height 942 let maxHeight = 0; 943 $multiCols.each(function () { 944 const height = $(this).outerHeight(); 945 if (height > maxHeight) { 946 maxHeight = height; 947 } 948 }); 949 950 $solutionsSubmenu.css({ 951 opacity: "", 952 visibility: "", 953 pointerEvents: "", 954 }); 955 956 $multiCols.each(function () { 957 this.style.removeProperty("display"); 958 this.style.removeProperty("visibility"); 959 this.style.removeProperty("position"); 960 this.style.removeProperty("opacity"); 961 this.style.removeProperty("width"); 962 this.style.removeProperty("left"); 963 }); 964 965 if (maxHeight > 0) { 966 $multiCols.each(function () { 967 this.style.setProperty("min-height", maxHeight + 20 + "px", "important"); 968 }); 969 } 970 } 971 972 $(window).on("load", function () { 973 equalizeSolutionsForHeight(); 974 }); 975 976 let equalizeRaf = null; 977 $(window).on("resize orientationchange", function () { 978 if (equalizeRaf) cancelAnimationFrame(equalizeRaf); 979 equalizeRaf = requestAnimationFrame(equalizeSolutionsForHeight); 980 }); 981 982 // Footer accordion 983 const FOOTER_MOBILE_BREAKPOINT = 991; 984 985 function getFooterCols() { 986 return $("#footer.aw-footer .footer-col"); 987 } 988 989 function getFooterCtaCols() { 990 return getFooterCols().filter(function () { 991 return $(this).find(".global-btn").length > 0; 992 }); 993 } 994 995 function getFooterAccordionCols() { 996 return getFooterCols().filter(function () { 997 return $(this).find(".global-btn").length === 0; 998 }); 999 } 1000 1001 function syncFooterCtaStyles() { 1002 const $ctaCols = getFooterCtaCols(); 1003 if (!$ctaCols.length) return; 1004 1005 $ctaCols.each(function () { 1006 const $col = $(this); 1007 const $btn = $col.find(".global-btn").first(); 1008 if (!$btn.length) return; 1009 1010 if (window.innerWidth <= FOOTER_MOBILE_BREAKPOINT) { 1011 $col.css("padding-top", "40px"); 1012 $btn.css({ 1013 marginLeft: "auto", 1014 marginRight: "auto", 1015 }); 1016 } else { 1017 $col.css("padding-top", ""); 1018 $btn.css({ 1019 marginLeft: "", 1020 marginRight: "", 1021 }); 1022 } 1023 }); 1024 } 1025 1026 function initFooterAccordion() { 1027 const $footerCols = getFooterCols(); 1028 const $accordionCols = getFooterAccordionCols(); 1029 1030 // Open first item by default 1031 if (window.innerWidth <= FOOTER_MOBILE_BREAKPOINT) { 1032 $accordionCols.first().addClass("is-open"); 1033 } 1034 1035 $accordionCols.off("click.footerAccordion").on("click.footerAccordion", "h5", function (e) { 1036 if (window.innerWidth > FOOTER_MOBILE_BREAKPOINT) return; 1037 1038 e.preventDefault(); 1039 const $col = $(this).closest(".footer-col"); 1040 const isOpen = $col.hasClass("is-open"); 1041 1042 $accordionCols.not($col).removeClass("is-open"); 1043 $col.toggleClass("is-open", !isOpen); 1044 }); 1045 1046 $footerCols 1047 .filter(function () { 1048 return $(this).find(".global-btn").length > 0; 1049 }) 1050 .removeClass("is-open"); 1051 syncFooterCtaStyles(); 1052 } 1053 1054 function resetFooterAccordion() { 1055 const $footerCols = getFooterCols(); 1056 const $accordionCols = getFooterAccordionCols(); 1057 1058 if (window.innerWidth > FOOTER_MOBILE_BREAKPOINT) { 1059 $accordionCols.removeClass("is-open"); 1060 syncFooterCtaStyles(); 1061 } else { 1062 if (!$accordionCols.filter(".is-open").length) { 1063 $accordionCols.first().addClass("is-open"); 1064 } 1065 $footerCols 1066 .filter(function () { 1067 return $(this).find(".global-btn").length > 0; 1068 }) 1069 .removeClass("is-open"); 1070 syncFooterCtaStyles(); 1071 } 1072 } 1073 1074 initFooterAccordion(); 1075 1076 $(window).on("resize orientationchange", function () { 1077 resetFooterAccordion(); 1078 }); 1079 1080 (function initStickyNavRow() { 1081 const header = document.getElementById("header"); 1082 if (!header) return; 1083 1084 const wrapper = header.querySelector(".wrapper.two-rows") || header.querySelector(".wrapper"); 1085 const firstRow = wrapper && wrapper.querySelector(".row:first-child"); 1086 const navRow = wrapper && wrapper.querySelector(".row:last-child"); 1087 if (!wrapper || !firstRow || !navRow || firstRow === navRow) return; 1088 1089 let rafId = null; 1090 1091 function getAdminBarOffset() { 1092 const adminBar = document.getElementById("wpadminbar"); 1093 if (!adminBar) return 0; 1094 1095 const style = window.getComputedStyle(adminBar); 1096 if (style.display === "none" || style.visibility === "hidden") return 0; 1097 1098 return adminBar.offsetHeight || 0; 1099 } 1100 1101 function isFirstRowVisible() { 1102 if (!firstRow) return false;
1103 1104 const style = window.getComputedStyle(firstRow); 1105 return style.display !== "none" && style.visibility !== "hidden" && firstRow.getClientRects().length > 0; 1106 } 1107 1108 function getStickyThreshold() { 1109 return isFirstRowVisible() ? firstRow.offsetHeight : 1; 1110 } 1111 1112 function syncSubmenuTop() { 1113 const submenus = document.getElementById("submenus"); 1114 const pageContainer = document.getElementById("page-container"); 1115 if (!submenus || !pageContainer) return; 1116 1117 let top = Math.round(navRow.getBoundingClientRect().bottom - pageContainer.getBoundingClientRect().top); 1118 1119 if (isDesktopViewport() && isAdminBarVisible()) { 1120 top += 32; 1121 } 1122 1123 if (top > 0) { 1124 submenus.style.top = top + "px"; 1125 } 1126 1127 syncSubmenuHorizontalPosition(); 1128 } 1129 1130 function syncMobileMenuTop() { 1131 const mobileMenu = document.getElementById("mobile-menu"); 1132 const pageContainer = document.getElementById("page-container"); 1133 if (!mobileMenu || !pageContainer) return; 1134 1135 const top = Math.round(navRow.getBoundingClientRect().bottom - pageContainer.getBoundingClientRect().top); 1136 if (top > 0) { 1137 mobileMenu.style.setProperty("--mobile-menu-top", top + "px"); 1138 mobileMenu.style.top = top + "px"; 1139 } 1140 } 1141 1142 function updateStickyNav() { 1143 wrapper.style.setProperty("--nav-row-height", navRow.offsetHeight + "px"); 1144 // Mirrored onto :root too â header is a sibling of <main>, so a 1145 // property set only on header's own wrapper never cascades down 1146 // into main's descendants (e.g. the Form Embed's scroll-margin-top). 1147 document.documentElement.style.setProperty("--nav-row-height", navRow.offsetHeight + "px"); 1148 1149 const threshold = getStickyThreshold(); 1150 const stuck = window.scrollY >= threshold; 1151 const stickyTop = getAdminBarOffset(); 1152 1153 header.classList.toggle("is-nav-stuck", stuck); 1154 1155 if (stuck) { 1156 navRow.style.top = stickyTop + "px"; 1157 wrapper.style.paddingBottom = navRow.offsetHeight + "px"; 1158 } else { 1159 navRow.style.removeProperty("top"); 1160 wrapper.style.removeProperty("padding-bottom"); 1161 } 1162 1163 syncSubmenuTop(); 1164 syncMobileMenuTop(); 1165 } 1166 1167 function scheduleUpdate() { 1168 if (rafId) return; 1169 1170 rafId = requestAnimationFrame(function () { 1171 rafId = null; 1172 updateStickyNav(); 1173 }); 1174 } 1175 1176 window.addEventListener("scroll", scheduleUpdate, { passive: true }); 1177 window.addEventListener("resize", scheduleUpdate); 1178 scheduleUpdate(); 1179 })(); 1180});
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.