functions.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 display 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. siteNavigation.find( '.menu-item-has-children > a' ).on( 'touchstart.twentysixteen', function( e ) {
  66. var el = $( this ).parent( 'li' );
  67. if ( ! el.hasClass( 'focus' ) ) {
  68. e.preventDefault();
  69. el.toggleClass( 'focus' );
  70. el.siblings( '.focus' ).removeClass( 'focus' );
  71. }
  72. } );
  73. } else {
  74. siteNavigation.find( '.menu-item-has-children > a' ).unbind( 'touchstart.twentysixteen' );
  75. }
  76. }
  77. if ( 'ontouchstart' in window ) {
  78. $( window ).on( 'resize.twentysixteen', toggleFocusClassTouchScreen );
  79. toggleFocusClassTouchScreen();
  80. }
  81. siteNavigation.find( 'a' ).on( 'focus.twentysixteen blur.twentysixteen', function() {
  82. $( this ).parents( '.menu-item' ).toggleClass( 'focus' );
  83. } );
  84. } )();
  85. // Add the default ARIA attributes for the menu toggle and the navigations.
  86. function onResizeARIA() {
  87. if ( window.innerWidth < 910 ) {
  88. if ( menuToggle.hasClass( 'toggled-on' ) ) {
  89. menuToggle.attr( 'aria-expanded', 'true' );
  90. } else {
  91. menuToggle.attr( 'aria-expanded', 'false' );
  92. }
  93. if ( siteHeaderMenu.hasClass( 'toggled-on' ) ) {
  94. siteNavigation.attr( 'aria-expanded', 'true' );
  95. socialNavigation.attr( 'aria-expanded', 'true' );
  96. } else {
  97. siteNavigation.attr( 'aria-expanded', 'false' );
  98. socialNavigation.attr( 'aria-expanded', 'false' );
  99. }
  100. menuToggle.attr( 'aria-controls', 'site-navigation social-navigation' );
  101. } else {
  102. menuToggle.removeAttr( 'aria-expanded' );
  103. siteNavigation.removeAttr( 'aria-expanded' );
  104. socialNavigation.removeAttr( 'aria-expanded' );
  105. menuToggle.removeAttr( 'aria-controls' );
  106. }
  107. }
  108. // Add 'below-entry-meta' class to elements.
  109. function belowEntryMetaClass( param ) {
  110. if ( body.hasClass( 'page' ) || body.hasClass( 'search' ) || body.hasClass( 'single-attachment' ) || body.hasClass( 'error404' ) ) {
  111. return;
  112. }
  113. $( '.entry-content' ).find( param ).each( function() {
  114. var element = $( this ),
  115. elementPos = element.offset(),
  116. elementPosTop = elementPos.top,
  117. entryFooter = element.closest( 'article' ).find( '.entry-footer' ),
  118. entryFooterPos = entryFooter.offset(),
  119. entryFooterPosBottom = entryFooterPos.top + ( entryFooter.height() + 28 ),
  120. caption = element.closest( 'figure' ),
  121. newImg;
  122. // Add 'below-entry-meta' to elements below the entry meta.
  123. if ( elementPosTop > entryFooterPosBottom ) {
  124. // Check if full-size images and captions are larger than or equal to 840px.
  125. if ( 'img.size-full' === param ) {
  126. // Create an image to find native image width of resized images (i.e. max-width: 100%).
  127. newImg = new Image();
  128. newImg.src = element.attr( 'src' );
  129. $( newImg ).load( function() {
  130. if ( newImg.width >= 840 ) {
  131. element.addClass( 'below-entry-meta' );
  132. if ( caption.hasClass( 'wp-caption' ) ) {
  133. caption.addClass( 'below-entry-meta' );
  134. caption.removeAttr( 'style' );
  135. }
  136. }
  137. } );
  138. } else {
  139. element.addClass( 'below-entry-meta' );
  140. }
  141. } else {
  142. element.removeClass( 'below-entry-meta' );
  143. caption.removeClass( 'below-entry-meta' );
  144. }
  145. } );
  146. }
  147. $( document ).ready( function() {
  148. body = $( document.body );
  149. $( window )
  150. .on( 'load.twentysixteen', onResizeARIA )
  151. .on( 'resize.twentysixteen', function() {
  152. clearTimeout( resizeTimer );
  153. resizeTimer = setTimeout( function() {
  154. belowEntryMetaClass( 'img.size-full' );
  155. belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
  156. }, 300 );
  157. onResizeARIA();
  158. } );
  159. belowEntryMetaClass( 'img.size-full' );
  160. belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
  161. } );
  162. } )( jQuery );