jQuery(document).ready(function($) { function getDataOffsetAdmin(el) { var dataOffsetAdmin = 0; if (document.getElementById('wpadminbar') != undefined) { dataOffsetAdmin = el.attr('data-offset-admin'); if (dataOffsetAdmin == undefined) { dataOffsetAdmin = 0; } } return dataOffsetAdmin; } // USEFUL TIP: // Remember that the waypoints are triggered in response to their proximity to the scrollTop position of the window. // For full documentation, go to the javascript Waypoints website. // Read the STANDARD Waypoints docs. NOT the "sticky shortcut" docs. We're NOT using the sticky shortcut method. // Everything below is standard Waypoints functions. // For each sticky element: Wrap it in a container and then wrap that container in another container // The parent (outer) container will become a waypoint relative to the window. This starts the initial sticky scrolling behavior. // The child (inner) container will become a waypoint relative to a large 'context' container. This element's height will limit how far the sticky element can travel. $('.sticky').wrap('
'); $('.sticky-container-child').wrap(''); // Set each parent container relative to the window and set their offsets. $('.sticky-container-parent').waypoint({ handler: function(direction) { var stickyItem = $($($(this).children()[0]).children()[0]); var minScreenWidth = $(stickyItem).attr('data-minimum-screen-width'); // Screen width less than this will disable the script. if (minScreenWidth == undefined) { minScreenWidth = 0; } console.log("Min screen width: " + minScreenWidth); console.log("Screen width: " + $(window).width()); if ($(window).width() < minScreenWidth) { console.log("Locking script"); stickyItem.removeClass('stuck'); stickyItem.removeClass('hit-bottom'); stickyItem.css('width', 'auto'); return 0; // Exit early. We've disabled the sticky behavior since we're in a columnized (mobile) view. } if (direction == 'down') { $(this).css({ 'height': stickyItem.outerHeight() }); console.log ( 'width: ' + stickyItem.outerWidth() ); stickyItem.css({ 'width': stickyItem.outerWidth() }); var dataOffsetAdmin = getDataOffsetAdmin(stickyItem); var dataOffsetTop = stickyItem.attr('data-offset-top'); if(dataOffsetTop == undefined) { dataOffsetTop = 0; } dataOffsetTop = parseInt(dataOffsetTop) + parseInt(dataOffsetAdmin); stickyItem.css('top', dataOffsetTop + 'px'); stickyItem.css('left', stickyItem.offset().left + 'px'); } else { $(this).css({ 'height':'100%' }); stickyItem.css({ 'width': '100%' }); console.log ( 'width: ' + stickyItem.outerWidth() ); } stickyItem.toggleClass('stuck', direction=='down'); }, offset: function(){ var stickyItem = $($($(this).children()[0]).children()[0]); var dataOffsetAdmin = getDataOffsetAdmin(stickyItem); var dataOffsetTop = stickyItem.attr('data-offset-top'); if (dataOffsetTop == undefined) { dataOffsetTop = 0; } return parseInt(dataOffsetTop) + parseInt(dataOffsetAdmin); } }); // Set child containers relative to the context element specified in each sticky element. $('.sticky-container-child').waypoint({ handler: function(direction) { var stickyItem = $($(this).children()[0]); var minScreenWidth = $(stickyItem).attr('data-minimum-screen-width'); // Screen width less than this will disable the script. if (minScreenWidth == undefined) { minScreenWidth = 0;} console.log("Min screen width: " + minScreenWidth); console.log("Screen width: " + $(window).width()); if ($(window).width() < minScreenWidth) { console.log("Locking script"); stickyItem.removeClass('stuck'); stickyItem.removeClass('hit-bottom'); stickyItem.css('width', 'auto'); return 0; // Exit early. We've disabled the sticky behavior since we're in a columnized (mobile) view. } if (direction == 'down') { // When this event fires, the sticky element can actually be way past where it should have stopped. Compute the position it should have been in and move it back. // Include a small margin of error so that it doesn't just appear to snap backward all the time. It should only be repositioned if its way past where it should be. var marginOfError = 50; vcntrSelector = stickyItem.attr('data-v-container'); var vcntrOffsetTop = 0; var vcntrOuterHeight = 0; if(vcntrSelector != undefined) { var vcntr = $(vcntrSelector); // // Vertical container which the sticky element should not be able to leave vcntrOffsetTop = vcntr.offset().top; vcntrOuterHeight = vcntr.outerHeight(); } // If data-offset-bottom is NOT set, we will return early because we don't need to check for a bottom waypoint. var offsetBottom = stickyItem.attr('data-offset-bottom'); if (offsetBottom == null) { return 0; } var idealPosition = vcntrOuterHeight + vcntrOffsetTop - stickyItem.outerHeight() - offsetBottom; if(stickyItem.offset().top - idealPosition > marginOfError) { stickyItem.css('top', idealPosition + 'px'); } else{ stickyItem.css('top', stickyItem.offset().top + 'px'); } stickyItem.removeClass('stuck'); stickyItem.addClass('hit-bottom'); stickyItem.css('left', $(this).parent().offset().left+ 'px'); } else { stickyItem.removeClass('hit-bottom'); stickyItem.addClass('stuck'); var dataOffsetAdmin = getDataOffsetAdmin(stickyItem); var dataOffsetTop = stickyItem.attr('data-offset-top'); if (dataOffsetTop == undefined) { dataOffsetTop = 0;} dataOffsetTop = parseInt(dataOffsetTop) + parseInt(dataOffsetAdmin); stickyItem.css('top', dataOffsetTop + 'px'); stickyItem.css('left', $(this).parent().offset().left + 'px'); } }, offset: function() { var stickyItem = $($($(this).children()[0])); var parentTop = $(this).parent().offset().top; vcntrSelector = stickyItem.attr('data-v-container'); var vcntrOffsetTop = 0; var vcntrOuterHeight = 0; if(vcntrSelector != undefined) { var vcntr = $(vcntrSelector); // // Vertical container which the sticky element should not be able to leave vcntrOffsetTop = vcntr.offset().top; vcntrOuterHeight = vcntr.outerHeight(); } var dataOffsetBottom = stickyItem.attr('data-offset-bottom'); if (dataOffsetBottom == undefined) { console.log('data-offset-bottom is null'); dataOffsetBottom = 0; } var dataOffsetAdmin = getDataOffsetAdmin(stickyItem); var dataOffsetTop = stickyItem.attr('data-offset-top'); if (dataOffsetTop == undefined) { console.log('data-offset-top is null'); dataOffsetTop = 0; } dataOffsetTop = parseInt(dataOffsetTop) + parseInt(dataOffsetAdmin); stickyItem.css('left', $(this).parent().offset().left+ 'px'); stickyItem.css('width', $(this).parent().outerWidth()+ 'px'); // As far as I can deduce, the child Waypoint is somehow impacted by the position of the parent Waypoint. I really don't understand why. // But the only way I could get the event to fire at the right position was to subtract off the parent's offset().top value. // I deduced this by monitoring the value of $(window).scrollTop() each time the main Waypoint event is triggered. var returnVal = 0 - (vcntrOuterHeight + vcntrOffsetTop - parentTop - dataOffsetTop - stickyItem.outerHeight() - dataOffsetBottom); return returnVal; } }); //Anytime the DOM is manipulated by a javascript, it can cause problems for Waypoints if using a computed offset. //Since Armstrong is recommending collapseomatic for expandable content, we're going to do a waypoints refresh anytime //a user clicks a collaseomatic element. //If you introduce another plugin or js that changes the DOM, you'll need to attach functions to do waypoint refreshes yourself. $('.collapseomatic').click(function(){ setTimeout( function() { $.waypoints('refresh'); }, 900); }) ; });