global.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /* global twentyseventeenScreenReaderText */
  2. (function( $ ) {
  3. // Variables and DOM Caching.
  4. var $body = $( 'body' ),
  5. $customHeader = $body.find( '.custom-header' ),
  6. $branding = $customHeader.find( '.site-branding' ),
  7. $navigation = $body.find( '.navigation-top' ),
  8. $navWrap = $navigation.find( '.wrap' ),
  9. $navMenuItem = $navigation.find( '.menu-item' ),
  10. $menuToggle = $navigation.find( '.menu-toggle' ),
  11. $menuScrollDown = $body.find( '.menu-scroll-down' ),
  12. $sidebar = $body.find( '#secondary' ),
  13. $entryContent = $body.find( '.entry-content' ),
  14. $formatQuote = $body.find( '.format-quote blockquote' ),
  15. isFrontPage = $body.hasClass( 'twentyseventeen-front-page' ) || $body.hasClass( 'home blog' ),
  16. navigationFixedClass = 'site-navigation-fixed',
  17. navigationHeight,
  18. navigationOuterHeight,
  19. navPadding,
  20. navMenuItemHeight,
  21. idealNavHeight,
  22. navIsNotTooTall,
  23. headerOffset,
  24. menuTop = 0,
  25. resizeTimer;
  26. // Ensure the sticky navigation doesn't cover current focused links.
  27. $( 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], [contenteditable]', '.site-content-contain' ).filter( ':visible' ).focus( function() {
  28. if ( $navigation.hasClass( 'site-navigation-fixed' ) ) {
  29. var windowScrollTop = $( window ).scrollTop(),
  30. fixedNavHeight = $navigation.height(),
  31. itemScrollTop = $( this ).offset().top,
  32. offsetDiff = itemScrollTop - windowScrollTop;
  33. // Account for Admin bar.
  34. if ( $( '#wpadminbar' ).length ) {
  35. offsetDiff -= $( '#wpadminbar' ).height();
  36. }
  37. if ( offsetDiff < fixedNavHeight ) {
  38. $( window ).scrollTo( itemScrollTop - ( fixedNavHeight + 50 ), 0 );
  39. }
  40. }
  41. });
  42. // Set properties of navigation.
  43. function setNavProps() {
  44. navigationHeight = $navigation.height();
  45. navigationOuterHeight = $navigation.outerHeight();
  46. navPadding = parseFloat( $navWrap.css( 'padding-top' ) ) * 2;
  47. navMenuItemHeight = $navMenuItem.outerHeight() * 2;
  48. idealNavHeight = navPadding + navMenuItemHeight;
  49. navIsNotTooTall = navigationHeight <= idealNavHeight;
  50. }
  51. // Make navigation 'stick'.
  52. function adjustScrollClass() {
  53. // Make sure we're not on a mobile screen.
  54. if ( 'none' === $menuToggle.css( 'display' ) ) {
  55. // Make sure the nav isn't taller than two rows.
  56. if ( navIsNotTooTall ) {
  57. // When there's a custom header image or video, the header offset includes the height of the navigation.
  58. if ( isFrontPage && ( $body.hasClass( 'has-header-image' ) || $body.hasClass( 'has-header-video' ) ) ) {
  59. headerOffset = $customHeader.innerHeight() - navigationOuterHeight;
  60. } else {
  61. headerOffset = $customHeader.innerHeight();
  62. }
  63. // If the scroll is more than the custom header, set the fixed class.
  64. if ( $( window ).scrollTop() >= headerOffset ) {
  65. $navigation.addClass( navigationFixedClass );
  66. } else {
  67. $navigation.removeClass( navigationFixedClass );
  68. }
  69. } else {
  70. // Remove 'fixed' class if nav is taller than two rows.
  71. $navigation.removeClass( navigationFixedClass );
  72. }
  73. }
  74. }
  75. // Set margins of branding in header.
  76. function adjustHeaderHeight() {
  77. if ( 'none' === $menuToggle.css( 'display' ) ) {
  78. // The margin should be applied to different elements on front-page or home vs interior pages.
  79. if ( isFrontPage ) {
  80. $branding.css( 'margin-bottom', navigationOuterHeight );
  81. } else {
  82. $customHeader.css( 'margin-bottom', navigationOuterHeight );
  83. }
  84. } else {
  85. $customHeader.css( 'margin-bottom', '0' );
  86. $branding.css( 'margin-bottom', '0' );
  87. }
  88. }
  89. // Set icon for quotes.
  90. function setQuotesIcon() {
  91. $( twentyseventeenScreenReaderText.quote ).prependTo( $formatQuote );
  92. }
  93. // Add 'below-entry-meta' class to elements.
  94. function belowEntryMetaClass( param ) {
  95. var sidebarPos, sidebarPosBottom;
  96. if ( ! $body.hasClass( 'has-sidebar' ) || (
  97. $body.hasClass( 'search' ) ||
  98. $body.hasClass( 'single-attachment' ) ||
  99. $body.hasClass( 'error404' ) ||
  100. $body.hasClass( 'twentyseventeen-front-page' )
  101. ) ) {
  102. return;
  103. }
  104. sidebarPos = $sidebar.offset();
  105. sidebarPosBottom = sidebarPos.top + ( $sidebar.height() + 28 );
  106. $entryContent.find( param ).each( function() {
  107. var $element = $( this ),
  108. elementPos = $element.offset(),
  109. elementPosTop = elementPos.top;
  110. // Add 'below-entry-meta' to elements below the entry meta.
  111. if ( elementPosTop > sidebarPosBottom ) {
  112. $element.addClass( 'below-entry-meta' );
  113. } else {
  114. $element.removeClass( 'below-entry-meta' );
  115. }
  116. });
  117. }
  118. /*
  119. * Test if inline SVGs are supported.
  120. * @link https://github.com/Modernizr/Modernizr/
  121. */
  122. function supportsInlineSVG() {
  123. var div = document.createElement( 'div' );
  124. div.innerHTML = '<svg/>';
  125. return 'http://www.w3.org/2000/svg' === ( 'undefined' !== typeof SVGRect && div.firstChild && div.firstChild.namespaceURI );
  126. }
  127. /**
  128. * Test if an iOS device.
  129. */
  130. function checkiOS() {
  131. return /iPad|iPhone|iPod/.test(navigator.userAgent) && ! window.MSStream;
  132. }
  133. /*
  134. * Test if background-attachment: fixed is supported.
  135. * @link http://stackoverflow.com/questions/14115080/detect-support-for-background-attachment-fixed
  136. */
  137. function supportsFixedBackground() {
  138. var el = document.createElement('div'),
  139. isSupported;
  140. try {
  141. if ( ! ( 'backgroundAttachment' in el.style ) || checkiOS() ) {
  142. return false;
  143. }
  144. el.style.backgroundAttachment = 'fixed';
  145. isSupported = ( 'fixed' === el.style.backgroundAttachment );
  146. return isSupported;
  147. }
  148. catch (e) {
  149. return false;
  150. }
  151. }
  152. // Fire on document ready.
  153. $( document ).ready( function() {
  154. // If navigation menu is present on page, setNavProps and adjustScrollClass.
  155. if ( $navigation.length ) {
  156. setNavProps();
  157. adjustScrollClass();
  158. }
  159. // If 'Scroll Down' arrow in present on page, calculate scroll offset and bind an event handler to the click event.
  160. if ( $menuScrollDown.length ) {
  161. if ( $( 'body' ).hasClass( 'admin-bar' ) ) {
  162. menuTop -= 32;
  163. }
  164. if ( $( 'body' ).hasClass( 'blog' ) ) {
  165. menuTop -= 30; // The div for latest posts has no space above content, add some to account for this.
  166. }
  167. if ( ! $navigation.length ) {
  168. navigationOuterHeight = 0;
  169. }
  170. $menuScrollDown.click( function( e ) {
  171. e.preventDefault();
  172. $( window ).scrollTo( '#primary', {
  173. duration: 600,
  174. offset: { top: menuTop - navigationOuterHeight }
  175. });
  176. });
  177. }
  178. adjustHeaderHeight();
  179. setQuotesIcon();
  180. if ( true === supportsInlineSVG() ) {
  181. document.documentElement.className = document.documentElement.className.replace( /(\s*)no-svg(\s*)/, '$1svg$2' );
  182. }
  183. if ( true === supportsFixedBackground() ) {
  184. document.documentElement.className += ' background-fixed';
  185. }
  186. });
  187. // If navigation menu is present on page, adjust it on scroll and screen resize.
  188. if ( $navigation.length ) {
  189. // On scroll, we want to stick/unstick the navigation.
  190. $( window ).on( 'scroll', function() {
  191. adjustScrollClass();
  192. adjustHeaderHeight();
  193. });
  194. // Also want to make sure the navigation is where it should be on resize.
  195. $( window ).resize( function() {
  196. setNavProps();
  197. setTimeout( adjustScrollClass, 500 );
  198. });
  199. }
  200. $( window ).resize( function() {
  201. clearTimeout( resizeTimer );
  202. resizeTimer = setTimeout( function() {
  203. belowEntryMetaClass( 'blockquote.alignleft, blockquote.alignright' );
  204. }, 300 );
  205. setTimeout( adjustHeaderHeight, 1000 );
  206. });
  207. // Add header video class after the video is loaded.
  208. $( document ).on( 'wp-custom-header-video-loaded', function() {
  209. $body.addClass( 'has-header-video' );
  210. });
  211. })( jQuery );