PageSourceSearch

https://www.spscommerce.com/wp-content/themes/divi-child-2016/js/global.js?ver=26.0924.1650

js spscommerce.com collected 2026-09-24 17:21:04 UTC 44,418 bytes, 1,180 lines download raw bytes

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.