1/* NewLife Shop â header, slide-in mobile menu. No dependencies. */ 2( function () { 3 'use strict'; 4 5 var nav = document.getElementById( 'nls-mnav' ); 6 var hdr = document.getElementById( 'nls-hdr' ); 7 var lastFocus = null; 8 var closeTimer = null; 9 10 function openers() { 11 return document.querySelectorAll( '[data-nls-mnav-open]' ); 12 } 13 14 function setExpanded( v ) { 15 openers().forEach( function ( b ) { 16 b.setAttribute( 'aria-expanded', v ? 'true' : 'false' ); 17 } ); 18 } 19 20 function isOpen() { 21 return nav && ! nav.hidden; 22 } 23 24 function open() { 25 if ( ! nav || isOpen() ) { 26 return; 27 } 28 clearTimeout( closeTimer ); 29 lastFocus = document.activeElement; 30 nav.hidden = false; 31 document.documentElement.classList.add( 'nls-mnav-lock' ); 32 setExpanded( true ); 33 // Next frame so the slide-in transition runs. 34 requestAnimationFrame( function () { 35 requestAnimationFrame( function () { 36 nav.classList.add( 'is-open' ); 37 var first = nav.querySelector( '.nls-mnav-close' ); 38 ( first || nav.querySelector( '.nls-mnav-panel' ) ).focus( { preventScroll: true } ); 39 } ); 40 } ); 41 } 42 43 function close( restoreFocus ) { 44 if ( ! isOpen() ) { 45 return; 46 } 47 nav.classList.remove( 'is-open' ); 48 document.documentElement.classList.remove( 'nls-mnav-lock' ); 49 setExpanded( false ); 50 var reduce = window.matchMedia && window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches; 51 closeTimer = setTimeout( function () { 52 nav.hidden = true; 53 }, reduce ? 0 : 280 ); 54 if ( restoreFocus !== false && lastFocus && lastFocus.focus ) { 55 lastFocus.focus( { preventScroll: true } ); 56 } 57 } 58 59 // Window capture runs before search.js / drawer.js (document capture), so 60 // the panel closes first and their overlays open on top. 61 window.addEventListener( 'click', function ( e ) { 62 var t = e.target; 63 if ( ! t || ! t.closest ) { 64 return; 65 } 66 if ( t.closest( '[data-nls-mnav-open]' ) ) { 67 e.preventDefault(); 68 open(); 69 return; 70 } 71 if ( ! isOpen() ) { 72 return; 73 } 74 if ( t.closest( '[data-nls-search-open], [data-nls-drawer-open]' ) && nav.contains( t ) ) { 75 close( false ); 76 return; // Let search.js / drawer.js handle it. 77 } 78 if ( t.closest( '[data-nls-mnav-close]' ) ) { 79 e.preventDefault(); 80 close(); 81 } 82 }, true ); 83 84 document.addEventListener( 'keydown', function ( e ) { 85 if ( ! isOpen() ) { 86 return; 87 } 88 if ( e.key === 'Escape' ) { 89 close(); 90 return; 91 } 92 if ( e.key !== 'Tab' ) { 93 return; 94 } 95 var f = nav.querySelectorAll( '.nls-mnav-panel a[href], .nls-mnav-panel button:not([disabled])' ); 96 if ( ! f.length ) { 97 return; 98 } 99 var first = f[ 0 ]; 100 var last = f[ f.length - 1 ]; 101 if ( e.shiftKey && ( document.activeElement === first || ! nav.contains( document.activeElement ) ) ) { 102 e.preventDefault(); 103 last.focus(); 104 } else if ( ! e.shiftKey && document.activeElement === last ) { 105 e.preventDefault(); 106 first.focus(); 107 } 108 } ); 109 110 // Desktop width reached while open (rotate / resize) â close. 111 if ( window.matchMedia ) { 112 var mq = window.matchMedia( '(min-width: 981px)' ); 113 var onMq = function () { 114 if ( mq.matches ) { 115 close( false ); 116 } 117 }; 118 if ( mq.addEventListener ) { 119 mq.addEventListener( 'change', onMq ); 120 } 121 } 122 123 // Compact header after scrolling. 124 if ( hdr ) { 125 var compact = false; 126 var ticking = false; 127 var check = function () { 128 ticking = false; 129 var c = window.scrollY > 60; 130 if ( c !== compact ) { 131 compact = c; 132 hdr.classList.toggle( 'is-compact', c ); 133 } 134 }; 135 window.addEventListener( 'scroll', function () { 136 if ( ! ticking ) { 137 ticking = true; 138 requestAnimationFrame( check ); 139 } 140 }, { passive: true } ); 141 check(); 142 } 143} )();
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.