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 */ 21bam.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 targetElement = ""; 95 activeClass = 'toggled-on'; 96 97 // Change the icon of the menu toggle button. 98 if ( element.classList.contains('menu-toggle') ) { 99 this.toggleIcon(element); 100 // Get the target element. 101 targetElement = document.querySelector(target); 102 } else { 103 var parentNavContainer = element.closest( '.bam-mobile-dropdown' ); 104 // Get the target element. 105 targetElement = parentNavContainer.querySelector(target); 106 } 107 108 element.classList.toggle(activeClass); 109 110 bamToggleAttribute(element, 'aria-expanded', 'true', 'false'); 111 112 if ( targetElement ) { 113 targetElement.classList.toggle(activeClass); 114 } 115 116 117 }, 118 119 toggle: function() { 120 var self = this; 121 122 document.querySelectorAll('*[data-toggle-target]').forEach( function( element ) { 123 element.addEventListener( 'click', function( event ) { 124 event.preventDefault(); 125 self.performToggle( element ); 126 } ); 127 } ); 128 }, 129 130 toggleIcon: function(element) { 131 var icon = element.querySelector('i.fas'); 132 133 if ( ! icon ) { 134 return false; 135 } 136 137 if( icon.classList.contains('fa-bars') ) { 138 icon.classList.remove('fa-bars'); 139 icon.classList.add('fa-times'); 140 } else if ( icon.classList.contains('fa-times') ) { 141 icon.classList.remove('fa-times'); 142 icon.classList.add('fa-bars'); 143 } 144 } 145}; 146 147/** 148 * Search Toggle. 149 */ 150bam.searchToggle = { 151 init: function() { 152 this.addListener(); 153 }, 154 155 toggle: function( element ) { 156 157 var navigationContainer = element.parentElement, 158 icon = navigationContainer.querySelector('i.fas'), 159 svgIconSearch = navigationContainer.querySelector('.bam-svg-search'), 160 svgIconClose = navigationContainer.querySelector('.bam-svg-times'), 161 searchBoxContainer = navigationContainer.querySelector('.bam-search-box-container'), 162 inputField = navigationContainer.querySelector('input.search-field'); 163 164 // Toggle active class. 165 searchBoxContainer.classList.toggle('active'); 166 167 // Toggle active class for element. 168 element.classList.toggle('toggled-on'); 169 170 // Toggle search icon. 171 if ( !svgIconSearch || !svgIconClose ) { 172 this.toggleIcon(icon); 173 } 174 175 // Focus the input field if the search box is displayed. 176 if( searchBoxContainer.classList.contains('active') ) { 177 inputField.focus(); 178 } 179 180 }, 181 182 addListener: function() { 183 184 var searchButton = document.querySelector('.bam-search-button-icon'); 185 186 if ( ! searchButton ) { 187 return false;
188 } 189 190 var self = this; 191 192 searchButton.addEventListener( 'click', function() { 193 self.toggle( this ); 194 } ); 195 196 }, 197 198 toggleIcon: function( icon ) { 199 200 if ( ! icon ) { 201 return false; 202 } 203 204 if ( icon.classList.contains('fa-search') ) { 205 icon.classList.remove('fa-search'); 206 icon.classList.add('fa-times'); 207 } else if ( icon.classList.contains('fa-times') ) { 208 icon.classList.remove('fa-times'); 209 icon.classList.add('fa-search'); 210 } 211 } 212 213}; 214 215/** 216 * Intrinsic Ratio Embeds 217 */ 218bam.intrinsicRatioVideos = { 219 220 init: function() { 221 this.makeFit(); 222 223 window.addEventListener( 'resize', function() { 224 this.makeFit(); 225 }.bind( this ) ); 226 }, 227 228 makeFit: function() { 229 document.querySelectorAll( 'iframe, object, video' ).forEach( function( video ) { 230 var ratio, iTargetWidth, 231 container = video.parentNode; 232 233 // Skip videos we want to ignore. 234 if ( video.classList.contains( 'intrinsic-ignore' ) || video.parentNode.classList.contains( 'intrinsic-ignore' ) ) { 235 return true; 236 } 237 238 if ( ! video.dataset.origwidth ) { 239 // Get the video element proportions. 240 video.setAttribute( 'data-origwidth', video.width ); 241 video.setAttribute( 'data-origheight', video.height ); 242 } 243 244 iTargetWidth = container.offsetWidth; 245 246 // Get ratio from proportions. 247 ratio = iTargetWidth / video.dataset.origwidth; 248 249 // Scale based on ratio, thus retaining proportions. 250 video.style.width = iTargetWidth + 'px'; 251 video.style.height = ( video.dataset.origheight * ratio ) + 'px'; 252 } ); 253 } 254 255}; 256 257/** 258 * Toggle an attribute 259 */ 260function bamToggleAttribute( element, attribute, trueVal, falseVal ) { 261 if ( trueVal === undefined ) { 262 trueVal = true; 263 } 264 if ( falseVal === undefined ) { 265 falseVal = false; 266 } 267 if ( element.getAttribute( attribute ) !== trueVal ) { 268 element.setAttribute( attribute, trueVal ); 269 } else { 270 element.setAttribute( attribute, falseVal ); 271 } 272} 273 274/** 275 * Is the DOM ready? 276 * 277 * This implementation is coming from https://gomakethings.com/a-native-javascript-equivalent-of-jquerys-ready-method/ 278 * 279 * @param {Function} fn Callback function to run. 280 */ 281function bamDomReady( fn ) { 282 if ( typeof fn !== 'function' ) { 283 return; 284 } 285 286 if ( document.readyState === 'interactive' || document.readyState === 'complete' ) { 287 return fn(); 288 } 289 290 document.addEventListener( 'DOMContentLoaded', fn, false ); 291} 292 293bamDomReady( function() { 294 bam.mobileMenu.init(); 295 bam.searchToggle.init(); 296 bam.keyboardNavigation.init(); 297 bam.intrinsicRatioVideos.init(); 298} );
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.