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