| 4109 | // Sticky header functionality. |
| 4110 | (function() { |
| 4111 | var parentContainer = $( '.wp-full-overlay-sidebar-content' ), |
| 4112 | changeContainer, getHeaderDimensions, releaseStickyHeader, resetStickyHeader, positionStickyHeader, |
| 4113 | activeHeader, lastScrollTop; |
| 4114 | |
| 4115 | // Determine which panel or section is currently expanded. |
| 4116 | changeContainer = function( container ) { |
| 4117 | var newInstance = container, |
| 4118 | expandedSection = api.state( 'expandedSection' ).get(), |
| 4119 | expandedPanel = api.state( 'expandedPanel' ).get(), |
| 4120 | headerElement, headerDimensions; |
| 4121 | |
| 4122 | // Release previously active header element. |
| 4123 | if ( activeHeader && activeHeader.element ) { |
| 4124 | releaseStickyHeader( activeHeader.element ); |
| 4125 | } |
| 4126 | |
| 4127 | if ( ! newInstance ) { |
| 4128 | if ( ! expandedSection && expandedPanel && expandedPanel.contentContainer ) { |
| 4129 | newInstance = expandedPanel; |
| 4130 | } else if ( ! expandedPanel && expandedSection && expandedSection.contentContainer ) { |
| 4131 | newInstance = expandedSection; |
| 4132 | } else { |
| 4133 | activeHeader = false; |
| 4134 | return; |
| 4135 | } |
| 4136 | } |
| 4137 | |
| 4138 | headerElement = newInstance.contentContainer.find( '.customize-section-title, .panel-meta' ).first(); |
| 4139 | if ( headerElement.length ) { |
| 4140 | headerDimensions = getHeaderDimensions( headerElement ); |
| 4141 | activeHeader = { |
| 4142 | instance: newInstance, |
| 4143 | element: headerElement, |
| 4144 | parent: headerElement.closest( '.customize-pane-child' ), |
| 4145 | top: headerDimensions.top, |
| 4146 | width: headerDimensions.width, |
| 4147 | height: headerDimensions.height |
| 4148 | }; |
| 4149 | if ( expandedSection ) { |
| 4150 | resetStickyHeader( activeHeader.element, activeHeader.parent ); |
| 4151 | } |
| 4152 | } else { |
| 4153 | activeHeader = false; |
| 4154 | } |
| 4155 | }; |
| 4156 | api.state( 'expandedSection' ).bind( changeContainer ); |
| 4157 | api.state( 'expandedPanel' ).bind( changeContainer ); |
| 4158 | |
| 4159 | // Throttled scroll event handler. |
| 4160 | parentContainer.on( 'scroll', _.throttle( function() { |
| 4161 | if ( ! activeHeader ) { |
| 4162 | return; |
| 4163 | } |
| 4164 | |
| 4165 | var scrollTop = parentContainer.scrollTop(), |
| 4166 | isScrollingUp = ( lastScrollTop ) ? scrollTop <= lastScrollTop : true; |
| 4167 | |
| 4168 | lastScrollTop = scrollTop; |
| 4169 | positionStickyHeader( activeHeader, scrollTop, isScrollingUp ); |
| 4170 | }, 8 ) ); |
| 4171 | |
| 4172 | // Release header element if it is sticky. |
| 4173 | releaseStickyHeader = function( headerElement ) { |
| 4174 | if ( ! headerElement.hasClass( 'is-sticky' ) ) { |
| 4175 | return; |
| 4176 | } |
| 4177 | headerElement |
| 4178 | .removeClass( 'is-sticky' ) |
| 4179 | .addClass( 'was-sticky' ) |
| 4180 | .css( 'top', parentContainer.scrollTop() + 'px' ); |
| 4181 | }; |
| 4182 | |
| 4183 | // Reset position of the sticky header. |
| 4184 | resetStickyHeader = function( headerElement, headerParent ) { |
| 4185 | headerElement |
| 4186 | .removeClass( 'maybe-sticky was-sticky is-sticky' ) |
| 4187 | .css( { |
| 4188 | width: '', |
| 4189 | top: '' |
| 4190 | } ); |
| 4191 | headerParent.css( 'padding-top', '' ); |
| 4192 | }; |
| 4193 | |
| 4194 | // Get header top position and height. |
| 4195 | getHeaderDimensions = function( headerElement ) { |
| 4196 | var dimensions = { |
| 4197 | height: headerElement.data( 'headerHeight' ), |
| 4198 | width: headerElement.data( 'headerWidth' ) |
| 4199 | }; |
| 4200 | if ( ! dimensions.height || ! dimensions.width ) { |
| 4201 | dimensions.height = headerElement.height(); |
| 4202 | dimensions.width = headerElement.width(); |
| 4203 | headerElement.data( { |
| 4204 | headerHeight: dimensions.height, |
| 4205 | headerWidth: dimensions.width |
| 4206 | } ); |
| 4207 | } |
| 4208 | return dimensions; |
| 4209 | }; |
| 4210 | |
| 4211 | // Reposition header on throttled `scroll` event. |
| 4212 | positionStickyHeader = function( header, scrollTop, isScrollingUp ) { |
| 4213 | var headerElement = header.element, |
| 4214 | headerParent = header.parent, |
| 4215 | headerHeight = header.height, |
| 4216 | headerWidth = header.width, |
| 4217 | headerTop = headerElement.data( 'top' ), |
| 4218 | maybeSticky, wasSticky, headerSiblingTop; |
| 4219 | |
| 4220 | // If in base position, then reset. |
| 4221 | if ( 0 === scrollTop ) { |
| 4222 | resetStickyHeader( headerElement, headerParent ); |
| 4223 | return; |
| 4224 | } |
| 4225 | |
| 4226 | maybeSticky = headerElement.hasClass( 'maybe-sticky' ); |
| 4227 | wasSticky = headerElement.hasClass( 'was-sticky' ); |
| 4228 | |
| 4229 | // Scrolled past the header height - element may become sticky now. |
| 4230 | if ( ! maybeSticky && scrollTop >= headerHeight ) { |
| 4231 | headerSiblingTop = headerParent.children( ':nth-child(2)' ).position().top; |
| 4232 | headerParent.css( 'padding-top', headerSiblingTop + 'px' ); |
| 4233 | headerElement |
| 4234 | .addClass( 'maybe-sticky' ) |
| 4235 | .css( 'width', headerWidth + 'px' ); |
| 4236 | } |
| 4237 | |
| 4238 | if ( isScrollingUp ) { |
| 4239 | headerElement.css( 'top', '' ); |
| 4240 | if ( ! wasSticky ) { |
| 4241 | headerElement.addClass( 'is-sticky' ); |
| 4242 | } else if ( wasSticky && headerTop >= scrollTop ) { |
| 4243 | headerElement |
| 4244 | .addClass( 'is-sticky' ) |
| 4245 | .removeClass( 'was-sticky' ); |
| 4246 | } |
| 4247 | } else { |
| 4248 | if ( wasSticky ) { |
| 4249 | if ( scrollTop >= headerHeight + headerTop ) { |
| 4250 | headerElement.removeClass( 'was-sticky' ); |
| 4251 | headerElement.css( 'top', '' ); |
| 4252 | } |
| 4253 | } else if ( headerElement.hasClass( 'is-sticky' ) ) { |
| 4254 | headerElement |
| 4255 | .removeClass( 'is-sticky' ) |
| 4256 | .addClass( 'was-sticky' ) |
| 4257 | .css( 'top', scrollTop + 'px' ) |
| 4258 | .data( 'top', scrollTop ); |
| 4259 | } |
| 4260 | } |
| 4261 | }; |
| 4262 | }()); |
| 4263 | |