1( function() { 2 'use strict'; 3 var allSubMenus = document.querySelectorAll( '.main-nav .sub-menu, .main-nav .children' ); 4 5 // Add missing aria roles and attributes for accessibility. 6 if ( allSubMenus ) { 7 allSubMenus.forEach( function( subMenu ) { 8 var parentLi = subMenu.closest( 'li' ); 9 var button = parentLi.querySelector( '.dropdown-menu-toggle[role="button"]' ); 10 11 if ( ! subMenu.id ) { 12 var itemId = parentLi.id 13 ? parentLi.id 14 : 'menu-item-' + Math.floor( Math.random() * 100000 ); // Just in case our menu item has no ID. 15 16 subMenu.id = itemId + '-sub-menu'; 17 } 18 19 // Bail if no button to update 20 if ( ! button ) { 21 button = parentLi.querySelector( 'a[role="button"]' ); 22 23 if ( ! button ) { 24 return; 25 } 26 } 27 28 button.setAttribute( 'aria-controls', subMenu.id ); 29 } ); 30 } 31 32 if ( 'querySelector' in document && 'addEventListener' in window ) { 33 /** 34 * matches() pollyfil 35 * 36 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 37 */ 38 if ( ! Element.prototype.matches ) { 39 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 40 } 41 42 /** 43 * closest() pollyfil 44 * 45 * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 46 * @param {Object} s The element to check. 47 * @return {Object} The closest object. 48 */ 49 if ( ! Element.prototype.closest ) { 50 Element.prototype.closest = function( s ) { 51 var el = this; 52 var ancestor = this; 53 if ( ! document.documentElement.contains( el ) ) { 54 return null; 55 } 56 do { 57 if ( ancestor.matches( s ) ) { 58 return ancestor; 59 } 60 ancestor = ancestor.parentElement; 61 } while ( ancestor !== null ); 62 return null; 63 }; 64 } 65 66 var getSiblings = function( elem ) { 67 return Array.prototype.filter.call( elem.parentNode.children, function( sibling ) { 68 return sibling !== elem; 69 } ); 70 }; 71 72 var allNavToggles = document.querySelectorAll( '.menu-toggle' ), 73 dropdownToggles = document.querySelectorAll( 'nav .dropdown-menu-toggle' ), 74 navLinks = document.querySelectorAll( 'nav .main-nav ul a' ), 75 mobileMenuControls = document.querySelector( '.mobile-menu-control-wrapper' ), 76 body = document.body, 77 htmlEl = document.documentElement, 78 i; 79 80 var enableDropdownArrows = function( nav ) { 81 if ( nav && body.classList.contains( 'dropdown-hover' ) ) { 82 var dropdownItems = nav.querySelectorAll( 'li.menu-item-has-children' ); 83 84 for ( i = 0; i < dropdownItems.length; i++ ) { 85 var toggle = dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ); 86 var parentLi = toggle.closest( 'li' ); 87 var subMenu = parentLi.querySelector( '.sub-menu, .children' ); 88 89 toggle.setAttribute( 'tabindex', '0' ); 90 toggle.setAttribute( 'role', 'button' ); 91 toggle.setAttribute( 'aria-expanded', 'false' ); 92 toggle.setAttribute( 'aria-controls', subMenu.id ); 93 toggle.setAttribute( 'aria-label', generatepressMenu.openSubMenuLabel ); 94 } 95 } 96 }; 97 98 var disableDropdownArrows = function( nav ) { 99 if ( nav && body.classList.contains( 'dropdown-hover' ) ) { 100 var dropdownItems = nav.querySelectorAll( 'li.menu-item-has-children' ); 101 102 for ( i = 0; i < dropdownItems.length; i++ ) { 103 dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ).removeAttribute( 'tabindex' ); 104 dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ).setAttribute( 'role', 'presentation' ); 105 dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ).removeAttribute( 'aria-expanded' ); 106 dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ).removeAttribute( 'aria-controls' ); 107 dropdownItems[ i ].querySelector( '.dropdown-menu-toggle' ).removeAttribute( 'aria-label' ); 108 } 109 } 110 }; 111 112 var setDropdownArrowAttributes = function( arrow ) { 113 if ( 'false' === arrow.getAttribute( 'aria-expanded' ) || ! arrow.getAttribute( 'aria-expanded' ) ) { 114 arrow.setAttribute( 'aria-expanded', 'true' ); 115 arrow.setAttribute( 'aria-label', generatepressMenu.closeSubMenuLabel ); 116 } else { 117 arrow.setAttribute( 'aria-expanded', 'false' ); 118 arrow.setAttribute( 'aria-label', generatepressMenu.openSubMenuLabel ); 119 } 120 }; 121 122 /** 123 * Start mobile menu toggle. 124 * 125 * @param {Object} e The event. 126 * @param {Object} _this The clicked item. 127 */ 128 var toggleNav = function( e, _this ) { 129 if ( ! _this ) { 130 _this = this; 131 } 132 133 var parentContainer = ''; 134 135 if ( _this.getAttribute( 'data-nav' ) ) { 136 parentContainer = document.getElementById( _this.getAttribute( 'data-nav' ) ); 137 } else {
138 parentContainer = document.getElementById( _this.closest( 'nav' ).getAttribute( 'id' ) ); 139 } 140 141 if ( ! parentContainer ) { 142 return; 143 } 144 145 var isExternalToggle = false; 146 147 if ( _this.closest( '.mobile-menu-control-wrapper' ) ) { 148 isExternalToggle = true; 149 } 150 151 var nav = parentContainer.getElementsByTagName( 'ul' )[ 0 ]; 152 153 if ( parentContainer.classList.contains( 'toggled' ) ) { 154 parentContainer.classList.remove( 'toggled' ); 155 htmlEl.classList.remove( 'mobile-menu-open' ); 156 157 if ( nav ) { 158 nav.setAttribute( 'aria-hidden', 'true' ); 159 } 160 161 _this.setAttribute( 'aria-expanded', 'false' ); 162 163 if ( isExternalToggle ) { 164 mobileMenuControls.classList.remove( 'toggled' ); 165 } else if ( mobileMenuControls && parentContainer.classList.contains( 'main-navigation' ) ) { 166 mobileMenuControls.classList.remove( 'toggled' ); 167 } 168 169 disableDropdownArrows( nav ); 170 } else { 171 parentContainer.classList.add( 'toggled' ); 172 htmlEl.classList.add( 'mobile-menu-open' ); 173 174 if ( nav ) { 175 nav.setAttribute( 'aria-hidden', 'false' ); 176 } 177 178 _this.setAttribute( 'aria-expanded', 'true' ); 179 180 if ( isExternalToggle ) { 181 mobileMenuControls.classList.add( 'toggled' ); 182 183 if ( mobileMenuControls.querySelector( '.search-item' ) ) { 184 if ( mobileMenuControls.querySelector( '.search-item' ).classList.contains( 'active' ) ) { 185 mobileMenuControls.querySelector( '.search-item' ).click(); 186 } 187 } 188 } else if ( mobileMenuControls && parentContainer.classList.contains( 'main-navigation' ) ) { 189 mobileMenuControls.classList.add( 'toggled' ); 190 } 191 192 enableDropdownArrows( nav ); 193 } 194 }; 195 196 for ( i = 0; i < allNavToggles.length; i++ ) { 197 allNavToggles[ i ].addEventListener( 'click', toggleNav, false ); 198 } 199 200 /** 201 * Open sub-menus 202 * 203 * @param {Object} e The event. 204 * @param {Object} _this The clicked item. 205 */ 206 var toggleSubNav = function( e, _this ) { 207 if ( ! _this ) { 208 _this = this; 209 } 210 211 if ( ( _this.closest( 'nav' ).classList.contains( 'toggled' ) || htmlEl.classList.contains( 'slide-opened' ) ) && ! body.classList.contains( 'dropdown-click' ) ) { 212 e.preventDefault(); 213 var closestLi = _this.closest( 'li' ); 214 215 setDropdownArrowAttributes( closestLi.querySelector( '.dropdown-menu-toggle' ) ); 216 217 if ( closestLi.querySelector( '.sub-menu' ) ) { 218 var subMenu = closestLi.querySelector( '.sub-menu' ); 219 } else { 220 subMenu = closestLi.querySelector( '.children' ); 221 } 222 223 if ( generatepressMenu.toggleOpenedSubMenus ) { 224 var siblings = getSiblings( closestLi ); 225 226 for ( i = 0; i < siblings.length; i++ ) { 227 if ( siblings[ i ].classList.contains( 'sfHover' ) ) { 228 siblings[ i ].classList.remove( 'sfHover' ); 229 siblings[ i ].querySelector( '.toggled-on' ).classList.remove( 'toggled-on' ); 230 setDropdownArrowAttributes( siblings[ i ].querySelector( '.dropdown-menu-toggle' ) ); 231 } 232 } 233 } 234 235 closestLi.classList.toggle( 'sfHover' ); 236 subMenu.classList.toggle( 'toggled-on' ); 237 } 238 239 e.stopPropagation(); 240 }; 241 242 for ( i = 0; i < dropdownToggles.length; i++ ) { 243 dropdownToggles[ i ].addEventListener( 'click', toggleSubNav, false ); 244 dropdownToggles[ i ].addEventListener( 'keypress', function( e ) { 245 if ( 'Enter' === e.key || ' ' === e.key ) { 246 toggleSubNav( e, this ); 247 } 248 }, false ); 249 } 250 251 /** 252 * Disable the mobile menu if our toggle isn't visible. 253 * Makes it possible to style mobile item with .toggled class. 254 */ 255 var checkMobile = function() { 256 var openedMobileMenus = document.querySelectorAll( '.toggled, .has-active-search' ); 257 258 for ( i = 0; i < openedMobileMenus.length; i++ ) { 259 var menuToggle = openedMobileMenus[ i ].querySelector( '.menu-toggle' ); 260 261 if ( mobileMenuControls && ! menuToggle.closest( 'nav' ).classList.contains( 'mobile-menu-control-wrapper' ) ) { 262 menuToggle = mobileMenuControls.querySelector( '.menu-toggle' ); 263 } 264 265 if ( menuToggle && menuToggle.offsetParent === null ) { 266 if ( openedMobileMenus[ i ].classList.contains( 'toggled' ) ) { 267 var remoteNav = false;
268 269 if ( openedMobileMenus[ i ].classList.contains( 'mobile-menu-control-wrapper' ) ) { 270 remoteNav = true; 271 } 272 273 if ( ! remoteNav ) { 274 // Navigation is toggled, but .menu-toggle isn't visible on the page (display: none). 275 var closestNav = openedMobileMenus[ i ].getElementsByTagName( 'ul' )[ 0 ], 276 closestNavItems = closestNav ? closestNav.getElementsByTagName( 'li' ) : [], 277 closestSubMenus = closestNav ? closestNav.getElementsByTagName( 'ul' ) : []; 278 } 279 280 document.activeElement.blur(); 281 openedMobileMenus[ i ].classList.remove( 'toggled' ); 282 283 htmlEl.classList.remove( 'mobile-menu-open' ); 284 menuToggle.setAttribute( 'aria-expanded', 'false' ); 285 286 if ( ! remoteNav ) { 287 for ( var li = 0; li < closestNavItems.length; li++ ) { 288 closestNavItems[ li ].classList.remove( 'sfHover' ); 289 } 290 291 for ( var sm = 0; sm < closestSubMenus.length; sm++ ) { 292 closestSubMenus[ sm ].classList.remove( 'toggled-on' ); 293 } 294 295 if ( closestNav ) { 296 closestNav.removeAttribute( 'aria-hidden' ); 297 } 298 } 299 300 disableDropdownArrows( openedMobileMenus[ i ] ); 301 } 302 303 if ( mobileMenuControls.querySelector( '.search-item' ) ) { 304 if ( mobileMenuControls.querySelector( '.search-item' ).classList.contains( 'active' ) ) { 305 mobileMenuControls.querySelector( '.search-item' ).click(); 306 } 307 } 308 } 309 } 310 }; 311 window.addEventListener( 'resize', checkMobile, false ); 312 window.addEventListener( 'orientationchange', checkMobile, false ); 313 314 if ( body.classList.contains( 'dropdown-hover' ) ) { 315 /** 316 * Do some essential things when menu items are clicked. 317 */ 318 for ( i = 0; i < navLinks.length; i++ ) { 319 navLinks[ i ].addEventListener( 'click', function( e ) { 320 // Remove sfHover class if we're going to another site. 321 if ( this.hostname !== window.location.hostname ) { 322 document.activeElement.blur(); 323 } 324 325 var closestNav = this.closest( 'nav' ); 326 if ( closestNav.classList.contains( 'toggled' ) || htmlEl.classList.contains( 'slide-opened' ) ) { 327 var url = this.getAttribute( 'href' ); 328 329 // Open the sub-menu if the link has no destination 330 if ( '#' === url || '' === url ) { 331 e.preventDefault(); 332 var closestLi = this.closest( 'li' ); 333 closestLi.classList.toggle( 'sfHover' ); 334 var subMenu = closestLi.querySelector( '.sub-menu' ); 335 336 if ( subMenu ) { 337 subMenu.classList.toggle( 'toggled-on' ); 338 } 339 } 340 } 341 }, false ); 342 } 343 } 344 345 if ( body.classList.contains( 'dropdown-hover' ) ) { 346 var menuBarItems = document.querySelectorAll( '.menu-bar-items .menu-bar-item > a' ); 347 348 /** 349 * Make menu items tab accessible when using the hover dropdown type 350 */ 351 var toggleFocus = function() { 352 if ( this.closest( 'nav' ).classList.contains( 'toggled' ) || this.closest( 'nav' ).classList.contains( 'slideout-navigation' ) ) { 353 return; 354 } 355 356 var self = this; 357 358 while ( -1 === self.className.indexOf( 'main-nav' ) ) { 359 if ( 'li' === self.tagName.toLowerCase() ) { 360 self.classList.toggle( 'sfHover' ); 361 } 362 363 self = self.parentElement; 364 } 365 }; 366 367 /** 368 * Make our menu bar items tab accessible. 369 */ 370 var toggleMenuBarItemFocus = function() { 371 if ( this.closest( 'nav' ).classList.contains( 'toggled' ) || this.closest( 'nav' ).classList.contains( 'slideout-navigation' ) ) { 372 return; 373 } 374 375 var self = this; 376 377 while ( -1 === self.className.indexOf( 'menu-bar-items' ) ) { 378 if ( self.classList.contains( 'menu-bar-item' ) ) { 379 self.classList.toggle( 'sfHover' ); 380 } 381 382 self = self.parentElement; 383 } 384 }; 385 386 for ( i = 0; i < navLinks.length; i++ ) { 387 navLinks[ i ].addEventListener( 'focus', toggleFocus ); 388 navLinks[ i ].addEventListener( 'blur', toggleFocus ); 389 } 390 391 for ( i = 0; i < menuBarItems.length; i++ ) { 392 menuBarItems[ i ].addEventListener( 'focus', toggleMenuBarItemFocus ); 393 menuBarItems[ i ].addEventListener( 'blur', toggleMenuBarItemFocus ); 394 } 395 } 396 397 /** 398 * Make hover dropdown touch-friendly. 399 */ 400 if ( 'ontouchend' in document.documentElement && document.body.classList.contains( 'dropdown-hover' ) ) { 401 var parentElements = document.querySelectorAll( '.sf-menu .menu-item-has-children' ); 402 403 for ( i = 0; i < parentElements.length; i++ ) { 404 parentElements[ i ].addEventListener( 'touchend', function( e ) { 405 // Bail on mobile
406 if ( this.closest( 'nav' ).classList.contains( 'toggled' ) ) { 407 return; 408 } 409 410 if ( e.touches.length === 1 || e.touches.length === 0 ) { 411 // Prevent touch events within dropdown bubbling down to document 412 e.stopPropagation(); 413 414 // Toggle hover 415 if ( ! this.classList.contains( 'sfHover' ) ) { 416 // Prevent link on first touch 417 if ( e.target === this || e.target.parentNode === this || e.target.parentNode.parentNode ) { 418 e.preventDefault(); 419 } 420 421 // Close other sub-menus. 422 var closestLi = this.closest( 'li' ), 423 siblings = getSiblings( closestLi ); 424 425 for ( i = 0; i < siblings.length; i++ ) { 426 if ( siblings[ i ].classList.contains( 'sfHover' ) ) { 427 siblings[ i ].classList.remove( 'sfHover' ); 428 } 429 } 430 431 this.classList.add( 'sfHover' ); 432 433 // Hide dropdown on touch outside 434 var closeDropdown, 435 thisItem = this; 436 437 document.addEventListener( 'touchend', closeDropdown = function( event ) { 438 event.stopPropagation(); 439 440 thisItem.classList.remove( 'sfHover' ); 441 document.removeEventListener( 'touchend', closeDropdown ); 442 } ); 443 } 444 } 445 } ); 446 } 447 } 448 } 449}() );
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.