1/** 2 * MyMoney.gov - JavaScript Initialization 3 */ 4 5(function() { 6 'use strict'; 7 8 function getSearchMenu() { 9 return document.getElementById('megamenu-search'); 10 } 11 12 function getSearchButtons() { 13 return Array.prototype.slice.call(document.querySelectorAll('.treas-search-nav .search-btn')); 14 } 15 16 function getMobileNavElements() { 17 return { 18 button: document.querySelector('.usa-menu-btn, .treas-burger-menu'), 19 nav: document.getElementById('navbarSupportedContent'), 20 close: document.querySelector('#navbarSupportedContent .usa-nav__close'), 21 overlay: document.querySelector('.usa-overlay') 22 }; 23 } 24 25 function isMobileNavigationViewport() { 26 return window.matchMedia && window.matchMedia('(max-width: 63.99em)').matches; 27 } 28 29 function focusableElements(container) { 30 if (!container) return []; 31 32 return Array.prototype.slice.call(container.querySelectorAll( 33 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])' 34 )).filter(function(element) { 35 return element.offsetWidth || element.offsetHeight || element.getClientRects().length; 36 }); 37 } 38 39 var mobileNavigationBackgroundStates = []; 40 41 function setMobileNavigationBackgroundHidden(hidden) { 42 var backgroundElements = Array.prototype.slice.call(document.querySelectorAll('main, footer')); 43 44 if (hidden) { 45 if (!mobileNavigationBackgroundStates.length) { 46 mobileNavigationBackgroundStates = backgroundElements.map(function(element) { 47 return { element: element, ariaHidden: element.getAttribute('aria-hidden') }; 48 }); 49 } 50 backgroundElements.forEach(function(element) { 51 element.setAttribute('aria-hidden', 'true'); 52 element.setAttribute('inert', ''); 53 }); 54 return; 55 } 56 57 mobileNavigationBackgroundStates.forEach(function(state) { 58 state.element.removeAttribute('inert'); 59 if (state.ariaHidden === null) { 60 state.element.removeAttribute('aria-hidden'); 61 } else { 62 state.element.setAttribute('aria-hidden', state.ariaHidden); 63 } 64 }); 65 mobileNavigationBackgroundStates = []; 66 } 67 68 function setMobileNavigationOpen(options) { 69 var elements = getMobileNavElements(); 70 if (!elements.button || !elements.nav) return; 71 72 var open = options.open; 73 elements.button.setAttribute('aria-expanded', open ? 'true' : 'false'); 74 elements.nav.setAttribute('aria-hidden', open || !isMobileNavigationViewport() ? 'false' : 'true'); 75 elements.nav.classList.toggle('is-visible', open); 76 if (elements.overlay) elements.overlay.classList.toggle('is-visible', open); 77 document.body.classList.toggle('usa-js-mobile-nav--active', open); 78 setMobileNavigationBackgroundHidden(open); 79 80 if (open) { 81 var firstTarget = elements.close || focusableElements(elements.nav)[0]; 82 if (firstTarget) window.setTimeout(function() { firstTarget.focus(); }, 0); 83 } else if (options.restoreFocus) { 84 elements.button.focus(); 85 } 86 } 87 88 function syncMobileNavigationAccessibility() { 89 var elements = getMobileNavElements(); 90 if (!elements.nav) return; 91 92 if (!isMobileNavigationViewport() && elements.button && elements.button.getAttribute('aria-expanded') === 'true') { 93 setMobileNavigationOpen({ open: false, restoreFocus: false }); 94 return; 95 } 96 97 elements.nav.setAttribute('aria-hidden', elements.button && elements.button.getAttribute('aria-expanded') === 'true' 98 ? 'false' 99 : (isMobileNavigationViewport() ? 'true' : 'false')); 100 } 101 102 function closeTopicsMenu() { 103 var topicsMenu = document.getElementById('megamenu-5'); 104 var topicsButtons = Array.prototype.slice.call(document.querySelectorAll('[aria-controls="megamenu-5"]')); 105 106 topicsButtons.forEach(function(button) { 107 button.setAttribute('aria-expanded', 'false'); 108 }); 109 110 if (topicsMenu) { 111 topicsMenu.setAttribute('hidden', ''); 112 topicsMenu.style.display = 'none'; 113 } 114 } 115 116 function isLocalHost() { 117 return /^localhost$|^127\.|^\[?::1\]?$/.test(window.location.hostname); 118 } 119 120 function isSlashlessPagePath(pathname) { 121 if (!pathname || pathname === '/' || pathname.endsWith('/')) return false;
122 return !/\.[a-z0-9]{2,8}$/i.test(pathname); 123 } 124 125 var localExactPathStorageKey = 'mymoneyLocalExactPathTarget'; 126 127 function localExactPathDisplayURL(targetUrl) { 128 return targetUrl.pathname + targetUrl.search + targetUrl.hash; 129 } 130 131 function localExactPathNavigationURL(targetUrl) { 132 var pathname = targetUrl.pathname; 133 if (!pathname.endsWith('/')) { 134 pathname += '/'; 135 } 136 return pathname + targetUrl.search + targetUrl.hash; 137 } 138 139 function sameLocalExactPath(currentUrl, targetUrl) { 140 var currentPath = currentUrl.pathname.replace(/\/+$/, '') || '/'; 141 var targetPath = targetUrl.pathname.replace(/\/+$/, '') || '/'; 142 return currentPath === targetPath && currentUrl.search === targetUrl.search && currentUrl.hash === targetUrl.hash; 143 } 144 145 function normalizeLocalExactPathAfterNavigation() { 146 if (!isLocalHost()) return; 147 148 var storedTarget; 149 try { 150 storedTarget = window.sessionStorage.getItem(localExactPathStorageKey); 151 if (!storedTarget) return; 152 } catch (error) { 153 return; 154 } 155 156 var targetUrl = new URL(storedTarget, window.location.origin); 157 var currentUrl = new URL(window.location.href); 158 159 try { 160 window.sessionStorage.removeItem(localExactPathStorageKey); 161 } catch (error) { 162 // Ignore storage cleanup failures; the URL is the important behavior. 163 } 164 165 if (sameLocalExactPath(currentUrl, targetUrl)) { 166 window.history.replaceState(window.history.state || {}, '', localExactPathDisplayURL(targetUrl)); 167 } 168 } 169 170 function navigateLocalExactPath(href) { 171 var targetUrl = new URL(href, window.location.href); 172 173 try { 174 window.sessionStorage.setItem(localExactPathStorageKey, localExactPathDisplayURL(targetUrl)); 175 } catch (error) { 176 // If storage is unavailable, direct slash navigation still avoids the redirect loop. 177 } 178 179 window.location.assign(localExactPathNavigationURL(targetUrl)); 180 } 181 182 function isLocalExactPathClick(event, link) { 183 if (!isLocalHost()) return false; 184 if (!link) return false; 185 if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) return false; 186 if (link.target || link.hasAttribute('download')) return false; 187 188 var href = link.getAttribute('href') || ''; 189 if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:') || href.startsWith('javascript:')) return false; 190 191 var targetUrl; 192 try { 193 targetUrl = new URL(href, window.location.href); 194 } catch (error) { 195 return false; 196 } 197 198 if (targetUrl.origin !== window.location.origin) return false; 199 return isSlashlessPagePath(targetUrl.pathname); 200 } 201 202 normalizeLocalExactPathAfterNavigation(); 203 204 function setSearchOpen(open) { 205 var searchMenu = getSearchMenu(); 206 var searchButtons = getSearchButtons(); 207 208 searchButtons.forEach(function(button) { 209 button.setAttribute('aria-expanded', open ? 'true' : 'false'); 210 }); 211 212 if (!searchMenu) return; 213 214 searchMenu.removeAttribute('hidden'); 215 searchMenu.style.display = open ? 'block' : 'none'; 216 217 if (open) { 218 closeTopicsMenu(); 219 window.setTimeout(function() { 220 var input = searchMenu.querySelector('input[name="query"]'); 221 if (input) input.focus(); 222 }, 0); 223 } 224 } 225 226 document.addEventListener('click', function(event) { 227 var target = event.target; 228 if (!target || !target.closest) return; 229 230 var exactPathLink = target.closest('a[href]'); 231 if (isLocalExactPathClick(event, exactPathLink)) { 232 event.preventDefault(); 233 event.stopPropagation(); 234 event.stopImmediatePropagation(); 235 navigateLocalExactPath(exactPathLink.getAttribute('href')); 236 return; 237 } 238 239 var searchButton = target.closest('.treas-search-nav .search-btn'); 240 if (searchButton) { 241 event.preventDefault(); 242 event.stopPropagation(); 243 event.stopImmediatePropagation(); 244 setSearchOpen(searchButton.getAttribute('aria-expanded') !== 'true'); 245 return; 246 } 247 248 if (target.closest('.usa-menu-btn, .treas-burger-menu')) { 249 event.preventDefault(); 250 event.stopPropagation(); 251 event.stopImmediatePropagation(); 252 setMobileNavigationOpen({ open: true, restoreFocus: false }); 253 return; 254 } 255 256 if (target.closest('.usa-nav__close') || target.closest('.usa-overlay')) { 257 event.preventDefault(); 258 event.stopPropagation(); 259 event.stopImmediatePropagation(); 260 setMobileNavigationOpen({ open: false, restoreFocus: true }); 261 return; 262 } 263 264 if (!target.closest('#megamenu-search') && !target.closest('.treas-search-nav')) { 265 setSearchOpen(false); 266 } 267 }, true); 268 269 document.addEventListener('keydown', function(event) { 270 if (event.key === 'Escape') { 271 setSearchOpen(false); 272 var mobileElements = getMobileNavElements(); 273 if (mobileElements.button && mobileElements.button.getAttribute('aria-expanded') === 'true') { 274 setMobileNavigationOpen({ open: false, restoreFocus: true }); 275 } 276 return; 277 } 278 279 var elements = getMobileNavElements(); 280 if (event.key !== 'Tab' || !elements.nav || elements.button?.getAttribute('aria-expanded') !== 'true') return; 281
282 var targets = focusableElements(elements.nav); 283 if (!targets.length) return; 284 285 var firstTarget = targets[0]; 286 var lastTarget = targets[targets.length - 1]; 287 if (event.shiftKey && document.activeElement === firstTarget) { 288 event.preventDefault(); 289 lastTarget.focus(); 290 } else if (!event.shiftKey && document.activeElement === lastTarget) { 291 event.preventDefault(); 292 firstTarget.focus(); 293 } 294 }); 295 296 window.addEventListener('resize', syncMobileNavigationAccessibility); 297 298 document.addEventListener('DOMContentLoaded', function() { 299 var searchMenu = getSearchMenu(); 300 syncMobileNavigationAccessibility(); 301 if (!searchMenu) return; 302 searchMenu.removeAttribute('hidden'); 303 searchMenu.style.display = 'none'; 304 getSearchButtons().forEach(function(button) { 305 button.setAttribute('aria-expanded', 'false'); 306 }); 307 }); 308})(); 309 310(function($) { 311 'use strict'; 312 313 // Run after a short delay to ensure all other scripts have loaded 314 $(window).on('load', function() { 315 // Delay to ensure we run AFTER site-scripts.js and USWDS handlers 316 setTimeout(initMyMoney, 100); 317 }); 318 319 // Also run on document ready as fallback 320 $(document).ready(function() { 321 setTimeout(initMyMoney, 100); 322 }); 323 324 var initialized = false; 325 326 function initMyMoney() { 327 if (initialized) return; 328 initialized = true; 329 330 // Accordions are initialized with hidden attribute - JS click handler toggles it 331 332 // Initialize Slick Slider for hero carousel 333 if ($('.slick__slider').length && !$('.slick__slider').hasClass('slick-initialized')) { 334 $('.slick__slider').slick({ 335 autoplay: true, 336 autoplaySpeed: 10000, 337 arrows: false, 338 dots: true, 339 fade: true, 340 speed: 500, 341 cssEase: 'ease-in-out', 342 pauseOnHover: true, 343 pauseOnFocus: true, 344 infinite: true 345 }); 346 } 347 348 // Remove any existing click handlers and add new ones 349 var $searchBtn = $('.search-btn'); 350 var $searchMenu = $('#megamenu-search'); 351 var $topicsBtn = $('button[aria-controls="megamenu-5"]'); 352 var $topicsMenu = $('#megamenu-5'); 353 354 // Ensure search menu starts hidden properly, unless the dependency-free 355 // click handler already opened it before jQuery finished initializing. 356 var searchIsExpanded = $searchBtn.filter('[aria-expanded="true"]').length > 0; 357 $searchMenu.removeAttr('hidden').css('display', searchIsExpanded ? 'block' : 'none'); 358 359 // Search button toggle - remove ALL click handlers first (including USWDS) 360 $searchBtn.off('click').on('click', function(e) { 361 e.preventDefault(); 362 e.stopPropagation(); 363 e.stopImmediatePropagation(); 364 365 var isExpanded = $(this).attr('aria-expanded') === 'true'; 366 367 // Close topics menu if open 368 $topicsMenu.attr('hidden', '').css('display', 'none'); 369 $topicsBtn.attr('aria-expanded', 'false'); 370 371 // Toggle search menu 372 if (isExpanded) { 373 $(this).attr('aria-expanded', 'false'); 374 $searchMenu.hide(); 375 } else { 376 $(this).attr('aria-expanded', 'true'); 377 $searchMenu.show(); 378 } 379 380 return false; 381 }); 382 383 // Topics dropdown toggle - match USWDS/live behavior by toggling aria and hidden. 384 $topicsBtn.off('click').on('click', function(e) { 385 e.preventDefault(); 386 e.stopPropagation(); 387 e.stopImmediatePropagation(); 388 389 var isExpanded = $(this).attr('aria-expanded') === 'true'; 390 391 // Close search menu if open 392 $searchMenu.css('display', 'none'); 393 $searchBtn.attr('aria-expanded', 'false'); 394 395 if (isExpanded) { 396 $(this).attr('aria-expanded', 'false'); 397 $topicsMenu.attr('hidden', '').css('display', 'none'); 398 } else { 399 $(this).attr('aria-expanded', 'true'); 400 $topicsMenu.removeAttr('hidden').css('display', 'block'); 401 } 402 403 return false; 404 }); 405 406 // Mobile menu toggle 407 $('.usa-menu-btn, .treas-burger-menu').off('click').on('click.mymoney', function(e) { 408 e.preventDefault(); 409 e.stopPropagation(); 410 e.stopImmediatePropagation(); 411 $('.usa-nav, .treas-main-nav').addClass('is-visible'); 412 $('.usa-overlay').addClass('is-visible'); 413 $('body').addClass('usa-js-mobile-nav--active'); 414 this.blur(); 415 return false;
416 }); 417 418 $('.usa-nav__close').off('click').on('click.mymoney', function(e) { 419 e.preventDefault(); 420 e.stopPropagation(); 421 e.stopImmediatePropagation(); 422 $('.usa-nav, .treas-main-nav').removeClass('is-visible'); 423 $('.usa-overlay').removeClass('is-visible'); 424 $('body').removeClass('usa-js-mobile-nav--active'); 425 return false; 426 }); 427 428 $('.usa-overlay').off('click.mymoney').on('click.mymoney', function(e) { 429 e.preventDefault(); 430 e.stopPropagation(); 431 $('.usa-nav, .treas-main-nav').removeClass('is-visible'); 432 $(this).removeClass('is-visible'); 433 $('body').removeClass('usa-js-mobile-nav--active'); 434 return false; 435 }); 436 437 // Government banner toggle - initialize and handle click 438 var $bannerContent = $('#gov-banner'); 439 var $bannerButton = $('.usa-banner__button'); 440 441 // Remove hidden attribute and set initial state via CSS 442 $bannerContent.removeAttr('hidden').css('display', 'none'); 443 444 $bannerButton.off('click.mymoney').on('click.mymoney', function(e) { 445 e.preventDefault(); 446 e.stopPropagation(); 447 var isExpanded = $(this).attr('aria-expanded') === 'true'; 448 449 $(this).attr('aria-expanded', !isExpanded); 450 if (isExpanded) { 451 $bannerContent.hide(); 452 } else { 453 $bannerContent.show(); 454 } 455 }); 456 457 // Close menus when clicking outside 458 $(document).off('click.mymoney-outside').on('click.mymoney-outside', function(e) { 459 // Close search menu 460 if (!$(e.target).closest('.treas-search-nav, #megamenu-search, .search-btn').length) { 461 $searchMenu.hide(); 462 $searchBtn.attr('aria-expanded', 'false'); 463 } 464 // Close topics menu 465 if (!$(e.target).closest('[aria-controls="megamenu-5"], #megamenu-5').length) { 466 $topicsBtn.attr('aria-expanded', 'false'); 467 $topicsMenu.attr('hidden', '').css('display', 'none'); 468 } 469 }); 470 } 471 472})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.