1var bam = bam || {}; 2 3// polyfill forEach 4// https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#Polyfill 5if ( window.NodeList && ! NodeList.prototype.forEach ) { 6 NodeList.prototype.forEach = function( callback, thisArg ) { 7 var i; 8 var len = this.length; 9 10 thisArg = thisArg || window; 11 12 for ( i = 0; i < len; i++ ) { 13 callback.call( thisArg, this[ i ], i, this ); 14 } 15 }; 16} 17 18/** 19 * Keyboard navigation support for menus 20 */ 21 bam.keyboardNavigation = { 22 23 init: function() { 24 this.initMenus(); 25 }, 26 27 // The focusMenuItems() function implements Keyboard Navigation in the Bam Menus 28 // by adding the '.focus' class to all 'li' items when the focus is on the 'a' element. 29 focusMenuItems: function(navigationId) { 30 var navigation = document.getElementById(navigationId); 31 32 // Return early if the navigation does not exist. 33 if ( ! navigation ) { 34 return; 35 } 36 37 const menu = navigation.getElementsByTagName( 'ul' )[ 0 ]; 38 39 // If menu is empty return early. 40 if ( 'undefined' === typeof menu ) { 41 return; 42 } 43 44 if ( ! menu.classList.contains( 'nav-menu' ) ) { 45 menu.classList.add( 'nav-menu' ); 46 } 47 48 // Get all the link elements within the menu. 49 var links = menu.getElementsByTagName( 'a' ); 50 51 // Toggle focus each time a menu link is focused or blurred. 52 for ( var link of links ) { 53 link.addEventListener( 'focus', toggleFocus, true ); 54 link.addEventListener( 'blur', toggleFocus, true ); 55 } 56 57 /** 58 * Sets or removes .foucs class on an element. 59 */ 60 function toggleFocus() { 61 var self = this; 62 // Move up through the ancestors of the current link until we hit .nav-menu 63 while ( ! self.classList.contains( 'nav-menu' ) ) { 64 // On li elements toggle the class .focus 65 if ( 'li' === self.tagName.toLowerCase() ) { 66 self.classList.toggle( 'focus' ); 67 } 68 self = self.parentNode; 69 } 70 } 71 }, 72 73 initMenus: function() { 74 var navigationIds = ['site-navigation', 'top-navigation']; 75 navigationIds.forEach(function(navigationId) { 76 this.focusMenuItems(navigationId); 77 }, this); 78 } 79}; 80 81/** 82 * Mobile Menu. 83 */ 84bam.mobileMenu = { 85 86 init: function() { 87 // Do the toggle. 88 this.toggle(); 89 }, 90 91 performToggle: function( element ) { 92 93 var target = element.dataset.toggleTarget, 94 activeClass = 'toggled-on'; 95 96 // Get the target element. 97 targetElement = document.querySelector(target); 98 99 // Change the icon of the menu toggle button. 100 if ( element.classList.contains('menu-toggle') ) { 101 this.toggleIcon(element); 102 } 103 104 element.classList.toggle(activeClass); 105 106 bamToggleAttribute(element, 'aria-expanded', 'true', 'false'); 107 108 targetElement.classList.toggle(activeClass); 109 110 }, 111 112 toggle: function() { 113 var self = this; 114 115 document.querySelectorAll('*[data-toggle-target]').forEach( function( element ) { 116 element.addEventListener( 'click', function( event ) { 117 event.preventDefault(); 118 self.performToggle( element ); 119 } ); 120 } ); 121 }, 122 123 toggleIcon: function(element) { 124 var icon = element.querySelector('i.fas'); 125 126 if ( ! icon ) { 127 return false; 128 } 129 130 if( icon.classList.contains('fa-bars') ) { 131 icon.classList.remove('fa-bars'); 132 icon.classList.add('fa-times'); 133 } else if ( icon.classList.contains('fa-times') ) { 134 icon.classList.remove('fa-times'); 135 icon.classList.add('fa-bars'); 136 } 137 } 138}; 139 140/** 141 * Search Toggle. 142 */ 143 bam.searchToggle = { 144 init: function() { 145 this.addListener(); 146 }, 147 148 toggle: function( element ) { 149 150 var navigationContainer = element.parentElement, 151 icon = navigationContainer.querySelector('i.fas'), 152 searchBoxContainer = navigationContainer.querySelector('.bam-search-box-container'), 153 inputField = navigationContainer.querySelector('input.search-field'); 154 155 // Toggle active class. 156 searchBoxContainer.classList.toggle('active'); 157 158 // Toggle search icon. 159 this.toggleIcon(icon); 160 161 // Focus the input field if the search box is displayed. 162 if( searchBoxContainer.classList.contains('active') ) { 163 inputField.focus(); 164 } 165 166 }, 167 168 addListener: function() { 169 170 var searchButton = document.querySelector('.bam-search-button-icon'); 171 172 if ( ! searchButton ) { 173 return false;
174 } 175 176 var self = this; 177 178 searchButton.addEventListener( 'click', function() { 179 self.toggle( this ); 180 } ); 181 182 }, 183 184 toggleIcon: function( icon ) { 185 if ( icon.classList.contains('fa-search') ) { 186 icon.classList.remove('fa-search'); 187 icon.classList.add('fa-times'); 188 } else if ( icon.classList.contains('fa-times') ) { 189 icon.classList.remove('fa-times'); 190 icon.classList.add('fa-search'); 191 } 192 } 193}; 194 195/** 196 * Intrinsic Ratio Embeds 197 * From TwentyTwenty WordPress theme. - Copyright (C) 2020 WordPress.org, GPLv2 or later 198 */ 199bam.intrinsicRatioVideos = { 200 201 init: function() { 202 this.makeFit(); 203 204 window.addEventListener( 'resize', function() { 205 this.makeFit(); 206 }.bind( this ) ); 207 }, 208 209 makeFit: function() { 210 document.querySelectorAll( 'iframe, object, video' ).forEach( function( video ) { 211 var ratio, iTargetWidth, 212 container = video.parentNode; 213 214 // Skip videos we want to ignore. 215 if ( video.classList.contains( 'intrinsic-ignore' ) || video.parentNode.classList.contains( 'intrinsic-ignore' ) ) { 216 return true; 217 } 218 219 if ( ! video.dataset.origwidth ) { 220 // Get the video element proportions. 221 video.setAttribute( 'data-origwidth', video.width ); 222 video.setAttribute( 'data-origheight', video.height ); 223 } 224 225 iTargetWidth = container.offsetWidth; 226 227 // Get ratio from proportions. 228 ratio = iTargetWidth / video.dataset.origwidth; 229 230 // Scale based on ratio, thus retaining proportions. 231 video.style.width = iTargetWidth + 'px'; 232 video.style.height = ( video.dataset.origheight * ratio ) + 'px'; 233 } ); 234 } 235 236}; 237 238/* Toggle an attribute */ 239function bamToggleAttribute( element, attribute, trueVal, falseVal ) { 240 if ( trueVal === undefined ) { 241 trueVal = true; 242 } 243 if ( falseVal === undefined ) { 244 falseVal = false; 245 } 246 if ( element.getAttribute( attribute ) !== trueVal ) { 247 element.setAttribute( attribute, trueVal ); 248 } else { 249 element.setAttribute( attribute, falseVal ); 250 } 251} 252 253/** 254 * Is the DOM ready? 255 * 256 * This implementation is coming from https://gomakethings.com/a-native-javascript-equivalent-of-jquerys-ready-method/ 257 * 258 * @param {Function} fn Callback function to run. 259 */ 260function bamDomReady( fn ) { 261 if ( typeof fn !== 'function' ) { 262 return; 263 } 264 265 if ( document.readyState === 'interactive' || document.readyState === 'complete' ) { 266 return fn(); 267 } 268 269 document.addEventListener( 'DOMContentLoaded', fn, false ); 270} 271 272bamDomReady( function() { 273 bam.mobileMenu.init(); 274 bam.searchToggle.init(); 275 bam.keyboardNavigation.init(); 276 bam.intrinsicRatioVideos.init(); 277} );
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.