functions.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* global screenReaderText */
  2. /**
  3. * Theme functions file.
  4. *
  5. * Contains handlers for navigation and widget area.
  6. */
  7. ( function( $ ) {
  8. var body, masthead, menuToggle, siteNavigation, socialNavigation, siteHeaderMenu, resizeTimer;
  9. function initMainNavigation( container ) {
  10. // Add dropdown toggle that displays child menu items.
  11. var dropdownToggle = $( '<button />', {
  12. 'class': 'dropdown-toggle',
  13. 'aria-expanded': false
  14. } ).append( $( '<span />', {
  15. 'class': 'screen-reader-text',
  16. text: screenReaderText.expand
  17. } ) );
  18. container.find( '.menu-item-has-children > a' ).after( dropdownToggle );
  19. // Toggle buttons and submenu items with active children menu items.
  20. container.find( '.current-menu-ancestor > button' ).addClass( 'toggled-on' );
  21. container.find( '.current-menu-ancestor > .sub-menu' ).addClass( 'toggled-on' );
  22. // Add menu items with submenus to aria-haspopup="true".
  23. container.find( '.menu-item-has-children' ).attr( 'aria-haspopup', 'true' );
  24. container.find( '.dropdown-toggle' ).click( function( e ) {
  25. var _this = $( this ),
  26. screenReaderSpan = _this.find( '.screen-reader-text' );
  27. e.preventDefault();
  28. _this.toggleClass( 'toggled-on' );
  29. _this.next( '.children, .sub-menu' ).toggleClass( 'toggled-on' );
  30. // jscs:disable
  31. _this.attr( 'aria-expanded', _this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
  32. // jscs:enable
  33. screenReaderSpan.text( screenReaderSpan.text() === screenReaderText.expand ? screenReaderText.collapse : screenReaderText.expand );
  34. } );
  35. }
  36. initMainNavigation( $( '.main-navigation' ) );
  37. masthead = $( '#masthead' );
  38. menuToggle = masthead.find( '#menu-toggle' );
  39. siteHeaderMenu = masthead.find( '#site-header-menu' );
  40. siteNavigation = masthead.find( '#site-navigation' );
  41. socialNavigation = masthead.find( '#social-navigation' );
  42. // Enable menuToggle.
  43. ( function() {
  44. // Return early if menuToggle is missing.
  45. if ( ! menuToggle.length ) {
  46. return;
  47. }
  48. // Add an initial values for the attribute.
  49. menuToggle.add( siteNavigation ).add( socialNavigation ).attr( 'aria-expanded', 'false' );
  50. menuToggle.on( 'click.twentysixteen', function() {
  51. $( this ).add( siteHeaderMenu ).toggleClass( 'toggled-on' );
  52. // jscs:disable
  53. $( this ).add( siteNavigation ).add( socialNavigation ).attr( 'aria-expanded', $( this ).add( siteNavigation ).add( socialNavigation ).attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
  54. // jscs:enable
  55. } );
  56. } )();
  57. // Fix sub-menus for touch devices and better focus for hidden submenu items for accessibility.
  58. ( function() {
  59. if ( ! siteNavigation.length || ! siteNavigation.children().length ) {
  60. return;
  61. }
  62. // Toggle `focus` class to allow submenu access on tablets.
  63. function toggleFocusClassTouchScreen() {
  64. if ( window.innerWidth >= 910 ) {
  65. $( document.body ).on( 'touchstart.twentysixteen', function( e ) {
  66. if ( ! $( e.target ).closest( '.main-navigation li' ).length ) {
  67. $( '.main-navigation li' ).removeClass( 'focus' );
  68. }
  69. } );
  70. siteNavigation.find( '.menu-item-has-children > a' ).on( 'touchstart.twentysixteen', function( e ) {
  71. var el = $( this ).parent( 'li' );
  72. if ( ! el.hasClass( 'focus' ) ) {
  73. e.preventDefault();
  74. el.toggleClass( 'focus' );
  75. el.siblings( '.focus' ).removeClass( 'focus' );
  76. }
  77. } );
  78. } else {
  79. siteNavigation.find( '.menu-item-has-children > a' ).unbind( 'touchstart.twentysixteen' );
  80. }
  81. }
  82. if ( 'ontouchstart' in window ) {
  83. $( window ).on( 'resize.twentysixteen', toggleFocusClassTouchScreen );
  84. toggleFocusClassTouchScreen();
  85. }
  86. siteNavigation.find( 'a' ).on( 'focus.twentysixteen blur.twentysixteen', function() {
  87. $( this ).parents( '.menu-item' ).toggleClass( 'focus' );
  88. } );
  89. } )();
  90. // Add the default ARIA attributes for the menu toggle and the navigations.
  91. function onResizeARIA() {
  92. if ( window.innerWidth < 910 ) {
  93. if ( menuToggle.hasClass( 'toggled-on' ) ) {
  94. menuToggle.attr( 'aria-expanded', 'true' );
  95. } else {
  96. menuToggle.attr( 'aria-expanded', 'false' );
  97. }
  98. if ( siteHeaderMenu.hasClass( 'toggled-on' ) ) {
  99. siteNavigation.attr( 'aria-expanded', 'true' );
  100. socialNavigation.attr( 'aria-expanded', 'true' );
  101. } else {
  102. siteNavigation.attr( 'aria-expanded', 'false' );
  103. socialNavigation.attr( 'aria-expanded', 'false' );
  104. }
  105. menuToggle.attr( 'aria-controls', 'site-navigation social-navigation' );
  106. } else {
  107. menuToggle.removeAttr( 'aria-expanded' );
  108. siteNavigation.removeAttr( 'aria-expanded' );
  109. socialNavigation.removeAttr( 'aria-expanded' );
  110. menuToggle.removeAttr( 'aria-controls' );
  111. }
  112. }
  113. // Add 'below-entry-meta' class to elements.
  114. function belowEntryMetaClass( param ) {
  115. if ( body.hasClass( 'page' ) || body.hasClass( 'search' ) || body.hasClass( 'single-attachment' ) || body.hasClass( 'error404' ) ) {
  116. return;
  117. }
  118. $( '.entry-content' ).find( param ).each( function() {
  119. var element = $( this ),
  120. elementPos = element.offset(),
  121. elementPosTop = elementPos.top,
  122. entryFooter = element.closest( 'article' ).find( '.entry-footer' ),
  123. entryFooterPos = entryFooter.offset(),
  124. entryFooterPosBottom = entryFooterPos.top + ( entryFooter.height() + 28 ),
  125. caption = element.closest( 'figure' ),
  126. newImg;
  127. // Add 'below-entry-meta' to elements below the entry meta.
  128. if ( elementPosTop > entryFooterPosBottom ) {
  129. // Check if full-size images and captions are larger than or equal to 840px.
  130. if ( 'img.size-full' === param ) {
  131. // Create an image to find native image width of resized images (i.e. max-width: 100%).
  132. newImg = new Image();
  133. newImg.src = element.attr( 'src' );
  134. $( newImg ).on( 'load.twentysixteen', function() {
  135. if ( newImg.width >= 840 ) {
  136. element.addClass( 'below-entry-meta' );
  137. if ( caption.hasClass( 'wp-caption' ) ) {
  138. caption.addClass( 'below-entry-meta' );
  139. caption.removeAttr( 'style' );
  140. }
  141. }
  142. } );
  143. } else {
  144. element.addClass( 'below-entry-meta' );
  145. }
  146. } else {
  147. element.removeClass( 'below-entry-meta' );
  148. caption.removeClass( 'below-entry-meta' );
  149. }
  150. } );
  151. }
  152. $( document ).ready( function() {
  153. body = $( document.body );
  154. $( window )
  155. .on( 'load.twentysixteen', onResizeARIA )
  156. .on( 'resize.twentysixteen', function() {
  157. clearTimeout( resizeTimer );
  158. resizeTimer = setTimeout( function() {
  159. belowEntryMetaClass( 'img.size-full' );
  160. belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
  161. }, 300 );
  162. onResizeARIA();
  163. } );
  164. belowEntryMetaClass( 'img.size-full' );
  165. belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
  166. } );
  167. } )( jQuery );