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 = "…"; 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.