diff --git a/jquery.sticky.js b/jquery.sticky.js index 7417c47..193d695 100644 --- a/jquery.sticky.js +++ b/jquery.sticky.js @@ -11,162 +11,215 @@ // might need to adjust the width in some cases. (function($) { - var defaults = { - topSpacing: 0, - bottomSpacing: 0, - className: 'is-sticky', - wrapperClassName: 'sticky-wrapper', - center: false, - getWidthFrom: '', - responsiveWidth: false - }, - $window = $(window), - $document = $(document), - sticked = [], - windowHeight = $window.height(), - scroller = function() { - var scrollTop = $window.scrollTop(), - documentHeight = $document.height(), - dwh = documentHeight - windowHeight, - extra = (scrollTop > dwh) ? dwh - scrollTop : 0; - - for (var i = 0; i < sticked.length; i++) { - var s = sticked[i], - elementTop = s.stickyWrapper.offset().top, - etse = elementTop - s.topSpacing - extra; - - if (scrollTop <= etse) { - if (s.currentTop !== null) { - s.stickyElement - .css('width', '') - .css('position', '') - .css('top', ''); - s.stickyElement.trigger('sticky-end', [s]).parent().removeClass(s.className); - s.currentTop = null; - } - } - else { - var newTop = documentHeight - s.stickyElement.outerHeight() - - s.topSpacing - s.bottomSpacing - scrollTop - extra; - if (newTop < 0) { - newTop = newTop + s.topSpacing; - } else { - newTop = s.topSpacing; - } - if (s.currentTop != newTop) { - s.stickyElement - .css('width', s.stickyElement.width()) - .css('position', 'fixed') - .css('top', newTop); - - if (typeof s.getWidthFrom !== 'undefined') { - s.stickyElement.css('width', $(s.getWidthFrom).width()); + var defaults = { + topSpacing: 0, + bottomSpacing: 0, + className: 'is-sticky', + wrapperClassName: 'sticky-wrapper', + center: false, + getWidthFrom: '', + responsiveWidth: false + }, + $window = $(window), + $document = $(document), + sticked = [], + windowHeight = $window.height(), + update = function() { + updateSize(); + scroller(); + }, + updateSize = function(sticky) { + var _sticked; + if(sticky) { + if(Object.prototype.toString.call(sticky) == '[object Array]') + { + _sticked = sticky; + } else { + _sticked = [sticky]; + } + } else { + _sticked = sticked; } - s.stickyElement.trigger('sticky-start', [s]).parent().addClass(s.className); - s.currentTop = newTop; - } - } - } - }, - resizer = function() { - windowHeight = $window.height(); - - for (var i = 0; i < sticked.length; i++) { - var s = sticked[i]; - if (typeof s.getWidthFrom !== 'undefined' && s.responsiveWidth === true) { - s.stickyElement.css('width', $(s.getWidthFrom).width()); - } - } - }, - methods = { - init: function(options) { - var o = $.extend({}, defaults, options); - return this.each(function() { - var stickyElement = $(this); - - var stickyId = stickyElement.attr('id'); - var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName - var wrapper = $('
') - .attr('id', stickyId + '-sticky-wrapper') - .addClass(o.wrapperClassName); - stickyElement.wrapAll(wrapper); - - if (o.center) { - stickyElement.parent().css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"}); - } - - if (stickyElement.css("float") == "right") { - stickyElement.css({"float":"none"}).parent().css({"float":"right"}); - } - - var stickyWrapper = stickyElement.parent(); - stickyWrapper.css('height', stickyElement.outerHeight()); - sticked.push({ - topSpacing: o.topSpacing, - bottomSpacing: o.bottomSpacing, - stickyElement: stickyElement, - currentTop: null, - stickyWrapper: stickyWrapper, - className: o.className, - getWidthFrom: o.getWidthFrom, - responsiveWidth: o.responsiveWidth - }); - }); - }, - update: scroller, - unstick: function(options) { - return this.each(function() { - var unstickyElement = $(this); - - var removeIdx = -1; - for (var i = 0; i < sticked.length; i++) - { - if (sticked[i].stickyElement.get(0) == unstickyElement.get(0)) - { - removeIdx = i; + for (var i = 0; i < _sticked.length; i++) { + var s = _sticked[i]; + if(s.isSticky) { + s.stickyWrapper.css('height', s.stickyElement.outerHeight()); + } else { + s.stickyWrapper.css('height', ''); + } } - } - if(removeIdx != -1) - { - sticked.splice(removeIdx,1); - unstickyElement.unwrap(); - unstickyElement.removeAttr('style'); - } - }); - } - }; + }, + scroller = function() { + var scrollTop = $window.scrollTop(), + documentHeight = $document.height(), + dwh = documentHeight - windowHeight, + scrollBottom = dwh-scrollTop, + extra = (scrollTop > dwh) ? dwh - scrollTop : 0; - // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): - if (window.addEventListener) { - window.addEventListener('scroll', scroller, false); - window.addEventListener('resize', resizer, false); - } else if (window.attachEvent) { - window.attachEvent('onscroll', scroller); - window.attachEvent('onresize', resizer); - } - - $.fn.sticky = function(method) { - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method ) { - return methods.init.apply( this, arguments ); - } else { - $.error('Method ' + method + ' does not exist on jQuery.sticky'); - } - }; - - $.fn.unstick = function(method) { - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method ) { - return methods.unstick.apply( this, arguments ); - } else { - $.error('Method ' + method + ' does not exist on jQuery.sticky'); + for (var i = 0; i < sticked.length; i++) { + var s = sticked[i], + elementTop = s.stickyWrapper.offset().top, + etse = elementTop - s.topSpacing - extra; + + if (scrollTop <= etse) { + if (s.currentTop !== null) { + s.isSticky = s.isStickyTop = s.isStickyBottom = false; + s.stickyElement + .css('position', '') + .css('top', ''); + + s.stickyWrapper.css('height',''); + + updateSize(s); + + s.currentTop = null; + } + } + else { + var newTop, + newBottom = s.bottomSpacing - scrollBottom, + tempTop = documentHeight - s.stickyElement.outerHeight() + - s.topSpacing - s.bottomSpacing - scrollTop - extra; + + if (tempTop < 0) { + newTop = tempTop + s.topSpacing; + } else { + newTop = s.topSpacing; + } + + if (s.currentTop != newTop) { + if(tempTop < 0) { + s.isSticky = s.isStickyBottom = true; + s.isStickyTop = false; + s.stickyElement + .css('position', 'fixed') + .css('top', '') + .css('bottom', newBottom); + } else { + s.isSticky = s.isStickyTop = true; + s.isStickyBottom = false; + s.stickyElement + .css('position', 'fixed') + .css('bottom', '') + .css('top', newTop); + } + + updateSize(s); + + if (typeof s.getWidthFrom !== 'undefined') { + s.stickyElement.css('width', $(s.getWidthFrom).width()); + } + + s.stickyElement.trigger('sticky-start', [s]).parent().addClass(s.className); + s.currentTop = newTop; + s.currentBottom = newBottom; + } + } + } + }, + resizer = function() { + windowHeight = $window.height(); + + for (var i = 0; i < sticked.length; i++) { + var s = sticked[i]; + if (typeof s.getWidthFrom !== 'undefined' && s.responsiveWidth === true) { + s.stickyElement.css('width', $(s.getWidthFrom).width()); + } + } + }, + methods = { + init: function(options) { + var o = $.extend({}, defaults, options); + return this.each(function() { + var stickyElement = $(this); + + var stickyId = stickyElement.attr('id'); + var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName + var wrapper = $('') + .attr('id', stickyId + '-sticky-wrapper') + .addClass(o.wrapperClassName); + stickyElement.wrapAll(wrapper); + + if (o.center) { + stickyElement.parent().css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"}); + } + + if (stickyElement.css("float") == "right") { + stickyElement.css({"float":"none"}).parent().css({"float":"right"}); + } + + var stickyWrapper = stickyElement.parent(); + stickyWrapper.css('height', stickyElement.outerHeight()); + sticked.push({ + topSpacing: o.topSpacing, + bottomSpacing: o.bottomSpacing, + stickyElement: stickyElement, + currentTop: null, + currentBottom: null, + stickyWrapper: stickyWrapper, + className: o.className, + getWidthFrom: o.getWidthFrom, + responsiveWidth: o.responsiveWidth, + isSticky: false, + isStickyTop: false, + isStickyBottom: false + }); + }); + }, + update: update, + unstick: function(options) { + return this.each(function() { + var unstickyElement = $(this); + + var removeIdx = -1; + for (var i = 0; i < sticked.length; i++) + { + if (sticked[i].stickyElement.get(0) == unstickyElement.get(0)) + { + removeIdx = i; + } + } + if(removeIdx != -1) + { + sticked.splice(removeIdx,1); + unstickyElement.unwrap(); + unstickyElement.removeAttr('style'); + } + }); + } + }; + + // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): + if (window.addEventListener) { + window.addEventListener('scroll', scroller, false); + window.addEventListener('resize', resizer, false); + } else if (window.attachEvent) { + window.attachEvent('onscroll', scroller); + window.attachEvent('onresize', resizer); } - }; - $(function() { - setTimeout(scroller, 0); - }); + $.fn.sticky = function(method) { + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method ) { + return methods.init.apply( this, arguments ); + } else { + $.error('Method ' + method + ' does not exist on jQuery.sticky'); + } + }; + + $.fn.unstick = function(method) { + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method ) { + return methods.unstick.apply( this, arguments ); + } else { + $.error('Method ' + method + ' does not exist on jQuery.sticky'); + } + + }; + $(function() { + setTimeout(scroller, 0); + }); })(jQuery);