1/** 2 * Makes "skip to content" link work correctly in IE9, Chrome, and Opera 3 * for better accessibility. 4 * 5 * @link http://www.nczonline.net/blog/2013/01/15/fixing-skip-to-content-links/ 6 */ 7 8 ( function() { 9 var isWebkit = navigator.userAgent.toLowerCase().indexOf( 'webkit' ) > -1, 10 isOpera = navigator.userAgent.toLowerCase().indexOf( 'opera' ) > -1, 11 isIE = navigator.userAgent.toLowerCase().indexOf( 'msie' ) > -1; 12 13 if ( ( isWebkit || isOpera || isIE ) && document.getElementById && window.addEventListener ) { 14 window.addEventListener( 'hashchange', function() { 15 var id = location.hash.substring( 1 ), 16 element; 17 18 if ( ! ( /^[A-z0-9_-]+$/.test( id ) ) ) { 19 return; 20 } 21 22 element = document.getElementById( id ); 23 24 if ( element ) { 25 if ( ! ( /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) ) ) { 26 element.tabIndex = -1; 27 } 28 29 element.focus(); 30 31 // Repositions the window on jump-to-anchor to account for admin bar and border height. 32 window.scrollBy( 0, -53 ); 33 } 34 }, false ); 35 } 36} )(); 37; 38/* global screenReaderText */ 39/** 40 * Theme functions file. 41 * 42 * Contains handlers for navigation and widget area. 43 */ 44( function () { 45 'use strict'; 46 47 var mainNav, masthead, menuToggle, siteNavigation, socialNavigation, siteHeaderMenu, resizeTimer; 48 49 function matches( el, sel ) { 50 if ( Element.prototype.matches ) { 51 return el.matches( sel ); 52 } 53 54 if ( Element.prototype.msMatchesSelector ) { 55 return el.msMatchesSelector( sel ); 56 } 57 } 58 59 // Based on https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 60 function closest( el, sel ) { 61 if ( el.closest ) { 62 return el.closest( sel ); 63 } 64 65 var current = el; 66 67 do { 68 if ( matches( el, sel ) ) { 69 return current; 70 } 71 current = current.parentElement || current.parentNode; 72 } while ( current !== null && current.nodeType === 1 ); 73 74 return null; 75 } 76 77 function forEachNode( parent, selector, fn ) { 78 var nodes = parent.querySelectorAll( selector ); 79 for ( var i = 0; i < nodes.length; i++ ) { 80 fn( nodes[ i ] ); 81 } 82 } 83 84 function initMainNavigation( container ) { 85 forEachNode( container, '.menu-item-has-children > a', function ( el ) { 86 // Add dropdown toggle that displays child menu items. 87 var dropdownToggle = document.createElement( 'button' ); 88 dropdownToggle.className = 'dropdown-toggle'; 89 dropdownToggle.setAttribute( 'aria-expanded', 'false' ); 90 91 var span = document.createElement( 'span' ); 92 span.className = 'screen-reader-text'; 93 span.textContent = screenReaderText.expand; 94 95 dropdownToggle.appendChild( span ); 96 97 el.parentNode.insertBefore( dropdownToggle, el.nextSibling ); 98 } ); 99 100 // Toggle buttons and submenu items with active children menu items. 101 forEachNode( container, '.current-menu-ancestor > button', function ( el ) { 102 el.classList.add( 'toggled-on' ); 103 } ); 104 forEachNode( container, '.current-menu-ancestor > .sub-menu', function ( el ) { 105 el.classList.add( 'toggled-on' ); 106 } ); 107 108 // Add menu items with submenus to aria-haspopup="true". 109 forEachNode( container, '.menu-item-has-children', function ( el ) { 110 el.setAttribute( 'aria-haspopup', 'true' ); 111 } ); 112 113 forEachNode( container, '.dropdown-toggle', function ( el ) { 114 el.addEventListener( 'click', function ( e ) { 115 var screenReaderSpan = el.querySelector( '.screen-reader-text' ); 116 117 e.preventDefault(); 118 el.classList.toggle( 'toggled-on' ); 119 var next = el.nextElementSibling; 120 if ( next && matches( next, '.children, .sub-menu' ) ) { 121 next.classList.toggle( 'toggled-on' ); 122 } 123 124 el.setAttribute( 125 'aria-expanded', 126 el.getAttribute( 'aria-expanded' ) === 'false' ? 'true' : 'false' 127 ); 128 screenReaderSpan.textContent = 129 screenReaderSpan.textContent === screenReaderText.expand ? screenReaderText.collapse: screenReaderText.expand; 130 } ); 131 } ); 132 } 133 134 mainNav = document.querySelector( '.main-navigation' ); 135 if ( mainNav ) { 136 initMainNavigation( mainNav ); 137 } 138 139 masthead = document.querySelector( '#masthead' ); 140 menuToggle = masthead && masthead.querySelector( '#menu-toggle' ); 141 siteHeaderMenu = masthead && masthead.querySelector( '#site-header-menu' ); 142 siteNavigation = masthead && masthead.querySelector( '#site-navigation' ); 143 socialNavigation = masthead && masthead.querySelector( '#social-navigation' ); 144 145 // Enable menuToggle. 146 ( function () { 147 // Return early if menuToggle is missing. 148 if ( ! menuToggle ) { 149 return; 150 } 151 152 var controls = [ menuToggle, siteNavigation, socialNavigation ].filter( Boolean ); 153 154 // Add an initial values for the attribute.
155 controls.forEach( function ( el ) { 156 el.setAttribute( 'aria-expanded', 'false' ); 157 } ); 158 159 menuToggle.addEventListener( 'click', function () { 160 menuToggle.classList.toggle( 'toggled-on' ); 161 siteHeaderMenu.classList.toggle( 'toggled-on' ); 162 163 var newVal = menuToggle.getAttribute( 'aria-expanded' ) === 'false' ? 'true' : 'false'; 164 controls.forEach( function ( el ) { 165 el.setAttribute( 'aria-expanded', newVal ); 166 } ); 167 } ); 168 } )(); 169 170 // Fix sub-menus for touch devices and better focus for hidden submenu items for accessibility. 171 ( function () { 172 if ( ! siteNavigation || ! siteNavigation.children.length ) { 173 return; 174 } 175 176 // Init `focus` class to allow submenu access on tablets. 177 function initFocusClassTouchScreen() { 178 document.body.addEventListener( 'touchstart', function ( e ) { 179 if ( ! closest( e.target, '.main-navigation li' ) ) { 180 forEachNode( document, '.main-navigation li', function ( el ) { 181 el.classList.remove( 'focus' ); 182 } ); 183 } 184 } ); 185 forEachNode( siteNavigation, '.menu-item-has-children > a', function ( link ) { 186 link.addEventListener( 'touchstart', function ( e ) { 187 if ( window.innerWidth >= 910 ) { 188 var el = link.parentElement; 189 190 if ( matches( el, 'li' ) && ! el.classList.contains( 'focus' ) ) { 191 e.preventDefault(); 192 el.classList.toggle( 'focus' ); 193 var children = el.parentElement.children; 194 for ( var i = 0; i < children.length; i++ ) { 195 if ( children[ i ] !== el ) { 196 children[ i ].classList.remove( 'focus' ); 197 } 198 } 199 } 200 } 201 } ); 202 } ); 203 } 204 205 function toggleFocus( el ) { 206 var item = closest( el, '.menu-item' ); 207 if ( item ) { 208 item.classList.toggle( 'focus' ); 209 } 210 } 211 212 if ( 'ontouchstart' in window ) { 213 initFocusClassTouchScreen(); 214 } 215 216 forEachNode( siteNavigation, 'a', function ( link ) { 217 link.addEventListener( 'focus', toggleFocus( link ) ); 218 link.addEventListener( 'blur', toggleFocus( link ) ); 219 } ); 220 } )(); 221 222 // Add the default ARIA attributes for the menu toggle and the navigations. 223 function onResizeARIA() { 224 if ( window.innerWidth < 910 ) { 225 if ( menuToggle && menuToggle.classList.contains( 'toggled-on' ) ) { 226 menuToggle.setAttribute( 'aria-expanded', 'true' ); 227 } else { 228 menuToggle.setAttribute( 'aria-expanded', 'false' ); 229 } 230 231 if ( siteHeaderMenu && siteHeaderMenu.classList.contains( 'toggled-on' ) ) { 232 siteNavigation && siteNavigation.setAttribute( 'aria-expanded', 'true' ); 233 socialNavigation && socialNavigation.setAttribute( 'aria-expanded', 'true' ); 234 } else { 235 siteNavigation && siteNavigation.setAttribute( 'aria-expanded', 'false' ); 236 socialNavigation && socialNavigation.setAttribute( 'aria-expanded', 'false' ); 237 } 238 239 menuToggle && menuToggle.setAttribute( 'aria-controls', 'site-navigation social-navigation' ); 240 } else { 241 menuToggle && menuToggle.removeAttribute( 'aria-expanded' ); 242 siteNavigation && siteNavigation.removeAttribute( 'aria-expanded' ); 243 socialNavigation && socialNavigation.removeAttribute( 'aria-expanded' ); 244 menuToggle && menuToggle.removeAttribute( 'aria-controls' ); 245 } 246 } 247 248 // Add 'below-entry-meta' class to elements. 249 function belowEntryMetaClass( selector ) { 250 if ( 251 document.body.classList.contains( 'page' ) || 252 document.body.classList.contains( 'search' ) || 253 document.body.classList.contains( 'single-attachment' ) || 254 document.body.classList.contains( 'error404' ) 255 ) { 256 return; 257 } 258 259 forEachNode( document, '.entry-content', function ( content ) { 260 forEachNode( content, selector, function ( element ) { 261 var elementPosTop = element.getBoundingClientRect().top; 262 var article = closest( element, 'article' ); 263 var entryFooter = article && article.querySelector( '.entry-footer' ); 264 var entryFooterPosBottom = 265 entryFooter ? entryFooter.getBoundingClientRect().top + entryFooter.offsetHeight + 28 : null; 266 var caption = closest( element, 'figure' ); 267 var next = element.nextSibling; 268 var figcaption = next && matches( next, 'figcaption' ) ? next : null; 269 var newImg; 270 271 // Add 'below-entry-meta' to elements below the entry meta. 272 if ( entryFooterPosBottom !== null && elementPosTop > entryFooterPosBottom ) { 273 // Check if full-size images and captions are larger than or equal to 840px. 274 if ( selector === 'img.size-full' || selector === '.wp-block-image img' ) { 275 // Create an image to find native image width of resized images (i.e. max-width: 100%). 276 newImg = new Image(); 277 newImg.src = element.getAttribute( 'src' ); 278 newImg.onload = function () { 279 if ( newImg.width >= 840 ) { 280 // Check if an image in an image block has a width attribute; if its value is less than 840, return. 281 if ( 282 selector === '.wp-block-image img' && 283 element.hasAttribute( 'width' ) && 284 element.getAttribute( 'width' ) < 840 285 ) { 286 return; 287 } 288 289 element.classList.add( 'below-entry-meta' ); 290 291 if ( caption && caption.classList.contains( 'wp-caption' ) ) { 292 caption.classList.add( 'below-entry-meta' ); 293 caption.removeAttribute( 'style' ); 294 } 295 296 if ( figcaption ) { 297 figcaption.classList.add( 'below-entry-meta' ); 298 } 299 } 300 }; 301 } else { 302 element.classList.add( 'below-entry-meta' ); 303 } 304 } else { 305 element.classList.remove( 'below-entry-meta' ); 306 caption && caption.classList.remove( 'below-entry-meta' ); 307 } 308 } ); 309 } ); 310 } 311
312 function init() { 313 window.addEventListener( 'load', onResizeARIA ); 314 window.addEventListener( 'resize', function () { 315 clearTimeout( resizeTimer ); 316 resizeTimer = setTimeout( function () { 317 belowEntryMetaClass( 'img.size-full' ); 318 belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' ); 319 belowEntryMetaClass( '.wp-block-image img' ); 320 }, 300 ); 321 onResizeARIA(); 322 } ); 323 324 belowEntryMetaClass( 'img.size-full' ); 325 belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' ); 326 belowEntryMetaClass( '.wp-block-image img' ); 327 } 328 329 if ( document.readyState === 'loading' ) { 330 document.addEventListener( 'DOMContentLoaded', init ); 331 } else { 332 init(); 333 } 334} )(); 335;
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.