PageSourceSearch

https://www.wm.edu/js/main.js?v=021926

js wm.edu collected 2026-09-24 08:27:05 UTC 28,179 bytes, 776 lines download raw bytes

1var winWidth = window.innerWidth;
2var wmSiteMenu = document.getElementById("wm-site-menu");
3
4
5/* ====================================
6Some Code to help correct anchor links when there is layout shift 
7in the page template, usually due to dynamic fetched content loaded into the DOM
8========================================== */
9async function scrollToHash(el) {
10    if (el) {
11        setTimeout(() => {
12          el.scrollIntoView({ behavior: 'instant' });
13        }, 600);
14    }
15    //console.log("scrolled");
16}
17// Select elements
18const infograms = document.querySelectorAll('.infogram-embed');
19infograms.forEach((infogram) => {
20    // Add the mutationObserver
21    const observer = new MutationObserver((mutationsList) => {
22      for (const mutation of mutationsList) {
23        if (mutation.type === 'childList') {
24          mutation.addedNodes.forEach((node) => {
25            // Ensure it's an actual Element node, not just whitespace text
26            if (node.nodeType === Node.ELEMENT_NODE) {
27                if (window.location.hash) {
28                    const targetElement = document.querySelector(window.location.hash);
29                    if (targetElement) {
30                        scrollToHash(targetElement);
31                    }
32                }
33            }
34          });
35        }
36      }
37    });
38    observer.observe(infogram, { childList: true, subtree: true });
39});
40
41
42
43//------------------------------------------ //
44function viewport() {
45  var e = window,
46    a = "inner";
47  if (!("innerWidth" in window)) {
48    a = "client";
49    e = document.documentElement || document.body;
50  }
51  return { width: e[a + "Width"], height: e[a + "Height"] };
52}
53
54
55// For old chosen selects- can remove once new one is published everywhere ~ March 1, 2026
56
57document.addEventListener("DOMContentLoaded", function() {
58  // Get a reference to the select element
59  const selectElement = document.querySelector("select.departmentDropdownMenu");
60
61  // Add the 'change' event listener
62  if(selectElement) {
63      selectElement.addEventListener("change", function(event) {
64        // The selected value is available via event.target.value
65        const selectedValue = event.target.value;
66    
67        if (selectedValue) {
68          window.location.href = selectedValue; // Navigates to the URL
69        }
70      });
71  }
72});
73
74
75
76// // ====================== BREADCRUMBS ============================== //
77
78// document.addEventListener("DOMContentLoaded", function () {
79
80//   // remove the 'no-js' class from html tag, add 'js'
81//   const html_tag = document.querySelector('html');
82//   html_tag.classList.remove('no-js');
83//   html_tag.classList.add('js');
84
85//   // BREADCRUMB POPPER
86//   if (
87//     document.querySelector(".m-breadcrumbs") &&
88//     document.querySelector(".m-breadcrumbs").length != 0
89//   ) {
90//     // Make sure Popper is loaded
91//     if (typeof Popper != "undefined") {
92//       var mySelector = "main .m-breadcrumbs";
93//       var breadLists = document.querySelectorAll(mySelector);
94
95//       var breadlistNum = 0;
96//       for (b=0; b<breadLists.length; b++) {
97//         var thisBreadList = breadLists[b];  
98//         var breadListItems = thisBreadList.getElementsByTagName("li");
99//         var numBreadListItems = breadListItems.length;
100//         if (numBreadListItems > 3) {
101//           var newCollapsedLinks = document.createElement("div");
102//           newCollapsedLinks.setAttribute("id", "collapsedlinks" + breadlistNum);
103//           for (i = 1; i < numBreadListItems - 2; ++i) {
104//             newCollapsedLinks.appendChild(breadListItems[1]); // as items are taken away, the "next" item remains index 1
105//           }
106//           newArrow = document.createElement("div");
107//           newArrow.setAttribute("id", "bc_arrow" + breadlistNum);
108//           newArrow.setAttribute("data-popper-arrow", "true");
109//           newCollapsedLinks.appendChild(newArrow);
110
111//           // ELLIPSE
112//           var newListItem = document.createElement("li");
113//           newListItem.setAttribute("class", "m-breadcrumbs__link");
114//           newButton = document.createElement("button");
115//           newButton.innerHTML = "&hellip;";
116//           newButton.setAttribute("aria-expanded", "false");
117//           newButton.setAttribute(
118//             "aria-controls",
119//             "collapsedlinks" + breadlistNum
120//           );
121//           newListItem.appendChild(newButton);
122//           thisBreadList.insertBefore(newListItem, thisBreadList.children[1]);
123//           thisBreadList.insertBefore(
124//             document.createTextNode("\n"),
125//             thisBreadList.children[2]
126//           );
127//           newListItem.appendChild(newCollapsedLinks);
128
129//           // create the Popper
130//           const button = thisBreadList.querySelector(
131//             ".m-breadcrumbs__link button"
132//           );
133//           const tooltip = thisBreadList.querySelector(
134//             "#collapsedlinks" + breadlistNum
135//           );
136
137//           let popperInstance = null;
138
139//           function create() {
140//             popperInstance = Popper.createPopper(button, tooltip, {
141//               placement: "bottom-start",
142//               modifiers: [
143//                 { name: "offset", options: { offset: [-5, 20] } },
144//                 {
145//                   name: "flip",
146//                   options: { behavior: ["top-start", "bottom-start"] },
147//                 },
148//               ],
149//             });
150//           }
151//           function destroy() {
152//             if (popperInstance) {
153//               popperInstance.destroy();
154//               popperInstance = null;
155//             }
156//           }
157//           function toggleLinks() {
158//             if (tooltip.hasAttribute("data-show")) {
159//               tooltip.removeAttribute("data-show");
160//               button.setAttribute("aria-expanded", "false");
161//               destroy();
162//             } else {
163//               tooltip.setAttribute("data-show", "");
164//               button.setAttribute("aria-expanded", "true");
165//               create();
166//             }
167//           }
168//           button.addEventListener("click", toggleLinks);
169//           document.addEventListener(
170//             "click",
171//             function (event) {
172//               if (event.target.closest(".m-breadcrumbs__link button")) return;
173//               if (tooltip.hasAttribute("data-show")) {
174//                 tooltip.removeAttribute("data-show");
175//                 button.setAttribute("aria-expanded", "false");
176//                 destroy();
177//               }
178//             },
179//             true
180//           );
181//         } else if (numBreadListItems == 1) {
182//           thisBreadList.style.display = "none";
183//         }
184
185//         breadlistNum++;
186//       } // end loop multiple breadcrumb lists
187//     }
188//   }
189// });
190
191
192
193
194// ======================== WM.EDU MENUS =============================== //
195
196document.addEventListener("DOMContentLoaded", function () {
197
198  // check if there's a topbar. if so, do all the menu thangs
199	if (document.querySelector(".wm-topbar")) {
200  
201    // VARIABLES
202
203    // topbar
204    var topBar = document.querySelector(".wm-topbar");
205    // site menu button
206    var menuBtn = document.querySelector(".wm-topbar .wm-js-site-menu-button");
207    // background
208    var menuBackdrop = document.querySelector(".menubackdrop-dark");
209    // site menu
210    var siteMenu = document.querySelector(".wm-site-menu");
211    // close site menu button
212    var closeSiteMenuBtn = document.querySelector(".wm-site-menu .wm-js-site-menu-button-close-x");
213    // primary wrapper of site menu content
214    var siteMenuPrimaryWrapper = document.querySelector(".wm-site-menu__primary-wrapper")[0];
215  
216
217
218    //------------------------------------------ //
219    // function - openMenus 
220    function openMenus(which, callback) {
221      if (which == "site") {
222        document.body.classList.add("menu-open");
223      } 
224  
225      //  set body to not scroll when menus are open
226      const body = document.body;
227  
228      if (!$("html").hasClass("modal-open")) {
229        freezeBackground(true);
230      }
231      
232      // callback function used for setting focus for keyboard tabbing
233      callback();
234      
235    } // end: openMenus()
236  
237    //------------------------------------------ //
238    // Callback function to set focus on search input that should be visble now.... 
239    // (sometimes it doesn't work on first attempt, so using an interval to poll it)
240    function focusSearchBox() {
241      var winWidth = window.innerWidth;
242      if (winWidth > 1023) {
243        // put cursor in search box on desktop
244        var input = document.getElementById("q");
245        var counter = 20;
246        var checkExist = setInterval(function () {
247          counter--;
248          if (input || counter === 0) {
249            input.focus();
250            input.style.outline = "none";
251            clearInterval(checkExist);
252          }
253        }, 100);
254      } else {
255        var thisClose = document.querySelector(
256          ".wm-site-menu .wm-js-site-menu-button-close-x"
257        );
258        if (thisClose) {
259          var counter = 20;
260          var checkExist = setInterval(function () {
261            counter--;
262            if (thisClose || counter === 0) {
263              thisClose.focus();
264              clearInterval(checkExist);
265            }
266          }, 100);
267        }
268      }
269    }
270  
271    // open site menu - topbar button click
272    menuBtn.onclick = function (e) {
273      e.preventDefault();
274      this.setAttribute("aria-expanded", "true");
275      openMenus("site", focusSearchBox);
276      return false;
277    };
278  
279    // CLOSE MENUS
280
281    // function - closeMenus
282    //------------------------------------------ //
283    function closeMenus(which) {
284  
285      if (which == "all") {
286        // close any expanded menu item, otherwise it is sticking around in keyboard tabbing even though the menus are visibility:hidden :(
287        var expandedMenuButton = document.querySelector(
288          '.primary-nav__togglesubmenu[aria-expanded="true"]'
289        );
290        if (expandedMenuButton) {
291          expandedMenuButton.click();
292        }
293        
294        if(document.body.classList.contains("menu-open")) {
295            // set focus to the topbar toggle menu button
296            menuBtn.focus();
297            document.body.classList.remove("menu-open");
298        }
299        
300      } 
301      else if (which == "site") {
302        document.body.classList.remove("menu-open");
303      } 
304  
305      // reset menu scroll to top
306      siteMenu.scrollTop = 0;
307  
308      // set scroll position of page to what it was before menu open
309      const body = document.body;
310  
311      freezeBackground(false);
312  
313      // close open accordian
314      const buttons = document.querySelectorAll(
315        ".primary-nav .wm-js-togglesubmenu"
316      );
317  
318      for (var b=0; b < buttons.length; b++) {
319        buttons[b].setAttribute("aria-expanded", "false");
320        buttons[b].nextElementSibling.setAttribute("aria-hidden", "true");
321      }
322    }
323  
324    // close menus - 'Esc' key close global and info for menus
325    document.onkeydown = function (evt) {
326      evt = evt || window.event;
327      if (evt.keyCode == 27) {
328        menuBtn.setAttribute("aria-expanded", "false");
329        closeMenus('all');
330      }
331    };
332  
333    // close menus - menubackdrop-dark click
334    menuBackdrop.onclick = function (event) {
335      menuBtn.setAttribute("aria-expanded", "false");
336      closeMenus('all');
337    };
338  
339    // close menus - close site menu button click
340    closeSiteMenuBtn.onclick = function (e) {
341      e.preventDefault();
342      menuBtn.setAttribute("aria-expanded", "false");
343      closeMenus("site");
344      return false;
345    };
346  
347    // function to make background not scroll when menus are open
348    let previousScrollY = 0;
349    //------------------------------------------ //
350    function freezeBackground(freeze) {
351      if (freeze) {
352        previousScrollY = window.scrollY;
353        var broadcastBarHeight;
354        $("broadcastBarTop")
355          ? (broadcastBarHeight = $("broadcastBarTop").outerHeight())
356          : (broadcastBarHeight = 0);
357        var topbarHeight = $(".wm-topbar").outerHeight();
358        var topbarY = $(".wm-topbar").offset();
359        topbarY = topbarY.top;
360  
361        if (previousScrollY == 0) {
362          contentOffset = topbarHeight + broadcastBarHeight;
363        } else {
364          contentOffset = topbarHeight;
365        }
366  
367        var scrollbarWidth =
368          window.innerWidth - document.documentElement.clientWidth;
369          
370        var homelogo = document.querySelector(".m-desktoplogo");
371  
372        $("html").addClass("modal-open").css({
373          marginTop: -previousScrollY,
374          overflow: "hidden",
375          left: 0,
376          right: 0,
377          top: 0,
378          bottom: 0,
379          position: "fixed",
380        });
381        $(".wm-topbar").css({
382          position: "absolute",
383          top: topbarY,
384          paddingRight: scrollbarWidth,
385        });
386        $("body").css({
387          paddingRight: scrollbarWidth,
388        });
389        $("#main-header").css({
390          marginTop: contentOffset,
391        });
392        
393      } else {
394        $("html").removeClass("modal-open").css({
395          marginTop: 0,
396          overflow: "visible",
397          left: "auto",
398          right: "auto",
399          top: "auto",
400          bottom: "auto",
401          position: "static",
402        });
403        $(".wm-topbar").css({
404          position: "",
405          top: 0,
406          paddingRight: 0,
407        });
408        $("body").css({
409          paddingRight: 0,
410        });
411        $("#main-header").css({
412          marginTop: 0,
413        });
414        if(previousScrollY && previousScrollY > 0) {
415            window.scrollTo({
416              top: previousScrollY,
417              behavior: 'instant'
418            });
419            previousScrollY = 0;
420        }
421      }
422    }
423  
424    // PRIMARY NAV ACCORDION SUBMENU
425
426    var accordion = $("body").find('[data-behavior="accordion"]');
427    var expandedClass = "is-expanded";
428    $.each(accordion, function () {
429      // loop through all accordions on the page
430  
431      var accordionItems = $(this).find('[data-binding="expand-accordion-item"]');
432  
433      $.each(accordionItems, function () {
434        // loop through all accordion items of each accordion
435        var $this = $(this);
436        var triggerBtn = $this.find('[data-binding="expand-accordion-trigger"]');
437  
438        var setHeight = function (nV) {
439          // set height of inner content for smooth animation
440          var innerContent = nV.find(".accordion__content-inner")[0],
441            maxHeight = $(innerContent).outerHeight(),
442            content = nV.find(".accordion__content")[0];
443  
444          if (!content.style.height || content.style.height === "0px") {
445            $(content).css("height", maxHeight);
446          } else {
447            $(content).css("height", "0px");
448          }
449        };
450  
451        var toggleClasses = function (event) {
452          var clickedItem = event.currentTarget;
453          var currentItem = $(clickedItem).parent();
454          var clickedContent = $(currentItem).find(".accordion__content");
455          var currentItemIsExpanded = currentItem.hasClass("is-expanded");
456  
457          $(".accordion__item").removeClass(expandedClass);
458          $(".accordion__title").attr("aria-selected", "false");
459          $(".accordion__title").attr("aria-expanded", "false");
460          $(".accordion__content").attr("aria-hidden", "true");
461          $(".accordion__content").css("height", "0px");
462  
463          if (!currentItemIsExpanded) {
464            $(currentItem).toggleClass(expandedClass);
465            setHeight(currentItem);
466            $(clickedItem).attr("aria-selected", "true");
467            $(clickedItem).attr("aria-expanded", "true");
468            $(clickedContent).attr("aria-hidden", "false");
469          } else {
470            $(clickedItem).attr("aria-selected", "false");
471            $(clickedItem).attr("aria-expanded", "false");
472            $(clickedContent).attr("aria-hidden", "true");
473          }
474        };
475  
476        triggerBtn.on("click", event, function (e) {
477          e.preventDefault();
478          toggleClasses(event);
479        });
480  
481        // open tabs if the spacebar or enter button is clicked whilst they are in focus
482        $(triggerBtn).on("keydown", event, function (e) {
483          if (e.keyCode === 13 || e.keyCode === 32) {
484            e.preventDefault();
485            toggleClasses(event);
486          }
487        });
488      }); // end .each accordion items
489    }); // end .each accordion
490  
491    // SEARCH SUGGESTIONS
492
493    var search_box = document.querySelector("input#q");
494    var common_area = document.querySelector(".wm-search__common-searches");
495    var common_items = document.querySelector(".wm-search__common-searches .items");
496    var suggestion_area = document.querySelector(".wm-search__suggested-results");
497    var suggested_items = document.querySelector(".wm-search__suggested-results .items");
498    var search_caption = document.querySelectorAll(".wm-search__caption");
499  
500    showCommonSearches();
501    hideSuggestionArea();
502  
503    search_box.addEventListener("input", showSuggestions);
504  
505    //------------------------------------------ //
506    function hideSuggestionArea() {
507      suggestion_area.classList.add("hidden");
508    }
509  
510    //------------------------------------------ //
511    function showSuggestionArea() {
512      search_box.classList.add("active");
513      suggestion_area.classList.remove("hidden");
514    }
515  
516    //------------------------------------------ //
517    function hideCommonArea() {
518      common_area.classList.add("hidden");
519    }
520  
521    //------------------------------------------ //
522    function showCommonArea() {
523      common_area.classList.remove("hidden");
524      search_caption[0].classList.remove("highlight");
525    }
526  
527    //------------------------------------------ //
528    function showCommonSearches() {
529      // only try ajax if on www, test-www or dev-www
530      if (window.location.href.indexOf("www.wm.edu") > -1) {
531          xhr = new XMLHttpRequest();
532          // the function that runs on return...
533          xhr.onreadystatechange = function () {
534            if (this.readyState == 4 && this.status == 200) {
535              var myArr = JSON.parse(this.responseText);
536              formatCommonSearches(myArr);
537            }
538          };
539          var common_address = "/atoz/common_searches_json.php";
540          xhr.open("GET", common_address, true);
541          xhr.send();
542      }
543    }
544  
545    //------------------------------------------ //
546    function formatCommonSearches(arr) {
547      var out = "";
548      // loop data items
549      for (i = 0; i < arr.length; i++) {
550        // fix the internal links...
551        reone = /^(http|\/\/)/i;
552        retwo = /(\.[a-zA-Z]+|\/)$/i;
553        var comp = arr[i].url;
554        if (!comp.match(reone) && !comp.match(retwo)) {
555          arr[i].url = comp + ".php";
556        }
557        out += '<li><a href="' + arr[i].url + '">' + arr[i].display + "</a></li>";
558      }
559      common_items.innerHTML = out;
560    }
561  
562    //------------------------------------------ //
563    function showSuggestions(e) {
564      var value = e.target.value;
565      if (value.length < 3) {
566        suggested_items.innerHTML = "";
567        hideSuggestionArea();
568        showCommonArea();
569        search_box.classList.remove("active");
570        search_caption[0].classList.remove("active");
571        return false;
572      } else {
573        hideCommonArea();
574        search_box.classList.add("active");
575        search_caption[0].classList.add("active");
576        // only try ajax if on www, test-www or dev-www
577        if (window.location.href.indexOf("www.wm.edu") > -1) {
578            xhr = new XMLHttpRequest();
579            // the function that runs on return...
580            xhr.onreadystatechange = function () {
581              if (this.readyState == 4 && this.status == 200) {
582                var myArr = JSON.parse(this.responseText);
583                formatSuggestions(myArr, value);
584              }
585            };
586            var suggestions_address = "/atoz/suggestions_json.php";
587            xhr.open("GET", suggestions_address, true);
588            xhr.send();
589        }
590      }
591    }
592  
593    //------------------------------------------ //
594    function formatSuggestions(arr, str) {
595      showSuggestionArea();
596      // alpha sort the arr
597      arr.sort(function (a, b) {
598        return a.display < b.display ? -1 : a.display > b.display ? 1 : 0;
599      });
600  
601      var out = "";
602      // convert str to array (search terms)
603      var terms = str.split(" ");
604  
605      // loop data items
606      for (i = 0; i < arr.length; i++) {
607        var matches_all_terms = 0;
608        // loop search terms
609        for (t = 0; t < terms.length; t++) {
610          if (terms[t].length > 2) {
611            // if display contains the term add to output
612            var re = new RegExp(terms[t], "gi");
613            var disp = arr[i].display;
614            if (disp.match(re)) {
615              matches_all_terms = 1;
616            } else {
617              matches_all_terms = 0;
618              break;
619            }
620          }
621        }
622        if (matches_all_terms == 1) {
623          // fix the internal links...
624          reone = /^(http|\/\/)/i;
625          retwo = /(\.[a-zA-Z]+|\/)$/i;
626          var comp = arr[i].url;
627          if (!comp.match(reone) && !comp.match(retwo)) {
628            arr[i].url = comp + ".php";
629          }
630          out +=
631            '<li><a href="' + arr[i].url + '">' + arr[i].display + "</a></li>";
632        }
633      }
634      if (out == "") {
635        search_caption[0].classList.add("highlight");
636        hideSuggestionArea();
637        //out = "Hit enter to search all of wm.edu";
638      }
639      suggested_items.innerHTML = out;
640    }
641
642  } // end: if .wm-topbar
643  
644    // Bulletproof Focus trap in W&M Menu
645    if (wmSiteMenu) {
646        let firstFocusableEl = null;
647        let lastFocusableEl = null;
648        let resizeTimeout;
649        let mutationObserver;
650    
651        let lastFocusedLinkInfo = null; // Captures the href of the last focused link
652    
653        // Visibility check
654        function isTrulyVisible(el) {
655            const style = window.getComputedStyle(el);
656            return !(
657                style.display === 'none' ||
658                style.visibility === 'hidden' ||
659                style.opacity === '0' ||
660                el.offsetParent === null ||
661                !el.getClientRects().length
662            );
663        }
664    
665        // Grabs all the focusable elements inside the container
666        // Excludes disabled elements and hidden elements (via the isTrulyVisible function)
667        // Returns only the elements that are focusable and visible
668        function getFocusableElements(container) {
669            const all = container.querySelectorAll(
670                'a[href]:not([disabled]):not([hidden]), button:not([disabled]):not([hidden]), textarea:not([disabled]):not([hidden]), input:not([disabled]):not([hidden]), select:not([disabled]):not([hidden])'
671            );
672            return Array.from(all).filter(el => !el.disabled && isTrulyVisible(el));
673        }
674        
675        // Unbinds old event listeners
676        // Removes any existing event listeners on the first and last focusable elements
677        function unbindFocusTrap() {
678            if (firstFocusableEl) firstFocusableEl.removeEventListener('keydown', handleFirst);
679            if (lastFocusableEl) lastFocusableEl.removeEventListener('keydown', handleLast);
680        }
681        
682        // Grabs all focusable elements in the container and assigns the first and last focusable elements
683        // If no focusable elements are found, it returns early to avoid errors
684        function bindFocusTrap(container) {
685            const focusableEls = getFocusableElements(container);
686            if (focusableEls.length === 0) return;
687    
688            firstFocusableEl = focusableEls[0];
689            lastFocusableEl = focusableEls[focusableEls.length - 1];
690    
691            // Check if the currently focused element is valid, otherwise jump to the last focused link
692            const active = document.activeElement;
693            const stillValid = focusableEls.includes(active);
694    
695            if (!stillValid && lastFocusedLinkInfo) {
696                // Try to find the last focused link by href
697                const match = focusableEls.find(el =>
698                    el.tagName === 'A' &&
699                    el.getAttribute('href')?.replace(/\/+$/, '') === lastFocusedLinkInfo.href.replace(/\/+$/, '')
700                );
701    
702                if (match) {
703                    match.focus(); // Focus the link that was last focused before resize
704                } else {
705                    firstFocusableEl.focus(); // Default to the first element
706                }
707    
708                lastFocusedLinkInfo = null; // Reset after restoring focus
709            }
710    
711            firstFocusableEl.addEventListener('keydown', handleFirst);
712            lastFocusableEl.addEventListener('keydown', handleLast);
713        }
714    
715        // Focus Trap Logic (First and Last Elements)
716        function handleFirst(e) {
717            if (e.key === 'Tab' && e.shiftKey) {
718                e.preventDefault();
719                lastFocusableEl?.focus();
720            }
721        }
722    
723        function handleLast(e) {
724            if (e.key === 'Tab' && !e.shiftKey) {
725                e.preventDefault();
726                firstFocusableEl?.focus();
727            }
728        }
729    
730        // Resets and re-applies the focus trap logic to esnure the focus management remains intact,
731        // keeping it in line with any DOM changes that may have occured, like when the layout switches
732        // between mobile and desktop views or when elements are added/removed dynamically
733        function refreshFocusTrap() {
734            unbindFocusTrap(); // remove any previously set event listeners or handlers related to the focus trap
735            bindFocusTrap(wmSiteMenu); // rebind the focus trap to the wmSiteMenu element
736        }
737    
738        // Captures focused element before performing any resize logic
739        // Stores the currently focused link and its href in lastFocusedLinkInfo
740        // 'A' is an anchor tag
741        function captureFocusedElement() {
742            const active = document.activeElement;
743            if (active?.tagName === 'A' && active?.href) {
744                lastFocusedLinkInfo = {
745                    href: active.getAttribute('href')
746                };
747            } else {
748                lastFocusedLinkInfo = null;
749            }
750        }
751    
752        // Captures the focused element before resize to ensure we can restore it
753        window.addEventListener('resize', () => {
754            captureFocusedElement();
755            clearTimeout(resizeTimeout);
756            resizeTimeout = setTimeout(() => {
757                refreshFocusTrap();
758            }, 400);
759        });
760    
761        // Watches for changes to the DOM inside wmSiteMenu.
762        // If changes are detected, it calls refreshFocusTrap() to ensure the focus trap remains accurate
763        mutationObserver = new MutationObserver(() => {
764            refreshFocusTrap(); // Reapply focus trap when DOM changes
765        });
766    
767        mutationObserver.observe(wmSiteMenu, {
768            attributes: true,
769            childList: true,
770            subtree: true
771        });
772    
773        refreshFocusTrap(); // Initial run
774    }
775
776}); // end: DOMContentLoaded listener

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.