github.com/mweagle/Sparta@v1.15.0/docs_source/themes/hugo-theme-learn/static/js/jquery.sticky.js (about) 1 // Sticky Plugin v1.0.4 for jQuery 2 // ============= 3 // Author: Anthony Garand 4 // Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk) 5 // Improvements by Leonardo C. Daronco (daronco) 6 // Created: 02/14/2011 7 // Date: 07/20/2015 8 // Website: http://stickyjs.com/ 9 // Description: Makes an element on the page stick on the screen as you scroll 10 // It will only set the 'top' and 'position' of your element, you 11 // might need to adjust the width in some cases. 12 13 (function (factory) { 14 if (typeof define === 'function' && define.amd) { 15 // AMD. Register as an anonymous module. 16 define(['jquery'], factory); 17 } else if (typeof module === 'object' && module.exports) { 18 // Node/CommonJS 19 module.exports = factory(require('jquery')); 20 } else { 21 // Browser globals 22 factory(jQuery); 23 } 24 }(function ($) { 25 var slice = Array.prototype.slice; // save ref to original slice() 26 var splice = Array.prototype.splice; // save ref to original slice() 27 28 var defaults = { 29 topSpacing: 0, 30 bottomSpacing: 0, 31 className: 'is-sticky', 32 wrapperClassName: 'sticky-wrapper', 33 center: false, 34 getWidthFrom: '', 35 widthFromWrapper: true, // works only when .getWidthFrom is empty 36 responsiveWidth: false, 37 zIndex: 'inherit' 38 }, 39 $window = $(window), 40 $document = $(document), 41 sticked = [], 42 windowHeight = $window.height(), 43 scroller = function() { 44 var scrollTop = $window.scrollTop(), 45 documentHeight = $document.height(), 46 dwh = documentHeight - windowHeight, 47 extra = (scrollTop > dwh) ? dwh - scrollTop : 0; 48 49 for (var i = 0, l = sticked.length; i < l; i++) { 50 var s = sticked[i], 51 elementTop = s.stickyWrapper.offset().top, 52 etse = elementTop - s.topSpacing - extra; 53 54 //update height in case of dynamic content 55 s.stickyWrapper.css('height', s.stickyElement.outerHeight()); 56 57 if (scrollTop <= etse) { 58 if (s.currentTop !== null) { 59 s.stickyElement 60 .css({ 61 'width': '', 62 'position': '', 63 'top': '', 64 'z-index': '' 65 }); 66 s.stickyElement.parent().removeClass(s.className); 67 s.stickyElement.trigger('sticky-end', [s]); 68 s.currentTop = null; 69 } 70 } 71 else { 72 var newTop = documentHeight - s.stickyElement.outerHeight() 73 - s.topSpacing - s.bottomSpacing - scrollTop - extra; 74 if (newTop < 0) { 75 newTop = newTop + s.topSpacing; 76 } else { 77 newTop = s.topSpacing; 78 } 79 if (s.currentTop !== newTop) { 80 var newWidth; 81 if (s.getWidthFrom) { 82 padding = s.stickyElement.innerWidth() - s.stickyElement.width(); 83 newWidth = $(s.getWidthFrom).width() - padding || null; 84 } else if (s.widthFromWrapper) { 85 newWidth = s.stickyWrapper.width(); 86 } 87 if (newWidth == null) { 88 newWidth = s.stickyElement.width(); 89 } 90 s.stickyElement 91 .css('width', newWidth) 92 .css('position', 'fixed') 93 .css('top', newTop) 94 .css('z-index', s.zIndex); 95 96 s.stickyElement.parent().addClass(s.className); 97 98 if (s.currentTop === null) { 99 s.stickyElement.trigger('sticky-start', [s]); 100 } else { 101 // sticky is started but it have to be repositioned 102 s.stickyElement.trigger('sticky-update', [s]); 103 } 104 105 if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) { 106 // just reached bottom || just started to stick but bottom is already reached 107 s.stickyElement.trigger('sticky-bottom-reached', [s]); 108 } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) { 109 // sticky is started && sticked at topSpacing && overflowing from top just finished 110 s.stickyElement.trigger('sticky-bottom-unreached', [s]); 111 } 112 113 s.currentTop = newTop; 114 } 115 116 // Check if sticky has reached end of container and stop sticking 117 var stickyWrapperContainer = s.stickyWrapper.parent(); 118 var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing); 119 120 if( unstick ) { 121 s.stickyElement 122 .css('position', 'absolute') 123 .css('top', '') 124 .css('bottom', 0) 125 .css('z-index', ''); 126 } else { 127 s.stickyElement 128 .css('position', 'fixed') 129 .css('top', newTop) 130 .css('bottom', '') 131 .css('z-index', s.zIndex); 132 } 133 } 134 } 135 }, 136 resizer = function() { 137 windowHeight = $window.height(); 138 139 for (var i = 0, l = sticked.length; i < l; i++) { 140 var s = sticked[i]; 141 var newWidth = null; 142 if (s.getWidthFrom) { 143 if (s.responsiveWidth) { 144 newWidth = $(s.getWidthFrom).width(); 145 } 146 } else if(s.widthFromWrapper) { 147 newWidth = s.stickyWrapper.width(); 148 } 149 if (newWidth != null) { 150 s.stickyElement.css('width', newWidth); 151 } 152 } 153 }, 154 methods = { 155 init: function(options) { 156 return this.each(function() { 157 var o = $.extend({}, defaults, options); 158 var stickyElement = $(this); 159 160 var stickyId = stickyElement.attr('id'); 161 var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName; 162 var wrapper = $('<div></div>') 163 .attr('id', wrapperId) 164 .addClass(o.wrapperClassName); 165 166 stickyElement.wrapAll(function() { 167 if ($(this).parent("#" + wrapperId).length == 0) { 168 return wrapper; 169 } 170 }); 171 172 var stickyWrapper = stickyElement.parent(); 173 174 if (o.center) { 175 stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"}); 176 } 177 178 if (stickyElement.css("float") === "right") { 179 stickyElement.css({"float":"none"}).parent().css({"float":"right"}); 180 } 181 182 o.stickyElement = stickyElement; 183 o.stickyWrapper = stickyWrapper; 184 o.currentTop = null; 185 186 sticked.push(o); 187 188 methods.setWrapperHeight(this); 189 methods.setupChangeListeners(this); 190 }); 191 }, 192 193 setWrapperHeight: function(stickyElement) { 194 var element = $(stickyElement); 195 var stickyWrapper = element.parent(); 196 if (stickyWrapper) { 197 stickyWrapper.css('height', element.outerHeight()); 198 } 199 }, 200 201 setupChangeListeners: function(stickyElement) { 202 if (window.MutationObserver) { 203 var mutationObserver = new window.MutationObserver(function(mutations) { 204 if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) { 205 methods.setWrapperHeight(stickyElement); 206 } 207 }); 208 mutationObserver.observe(stickyElement, {subtree: true, childList: true}); 209 } else { 210 if (window.addEventListener) { 211 stickyElement.addEventListener('DOMNodeInserted', function() { 212 methods.setWrapperHeight(stickyElement); 213 }, false); 214 stickyElement.addEventListener('DOMNodeRemoved', function() { 215 methods.setWrapperHeight(stickyElement); 216 }, false); 217 } else if (window.attachEvent) { 218 stickyElement.attachEvent('onDOMNodeInserted', function() { 219 methods.setWrapperHeight(stickyElement); 220 }); 221 stickyElement.attachEvent('onDOMNodeRemoved', function() { 222 methods.setWrapperHeight(stickyElement); 223 }); 224 } 225 } 226 }, 227 update: scroller, 228 unstick: function(options) { 229 return this.each(function() { 230 var that = this; 231 var unstickyElement = $(that); 232 233 var removeIdx = -1; 234 var i = sticked.length; 235 while (i-- > 0) { 236 if (sticked[i].stickyElement.get(0) === that) { 237 splice.call(sticked,i,1); 238 removeIdx = i; 239 } 240 } 241 if(removeIdx !== -1) { 242 unstickyElement.unwrap(); 243 unstickyElement 244 .css({ 245 'width': '', 246 'position': '', 247 'top': '', 248 'float': '', 249 'z-index': '' 250 }) 251 ; 252 } 253 }); 254 } 255 }; 256 257 // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): 258 if (window.addEventListener) { 259 window.addEventListener('scroll', scroller, false); 260 window.addEventListener('resize', resizer, false); 261 } else if (window.attachEvent) { 262 window.attachEvent('onscroll', scroller); 263 window.attachEvent('onresize', resizer); 264 } 265 266 $.fn.sticky = function(method) { 267 if (methods[method]) { 268 return methods[method].apply(this, slice.call(arguments, 1)); 269 } else if (typeof method === 'object' || !method ) { 270 return methods.init.apply( this, arguments ); 271 } else { 272 $.error('Method ' + method + ' does not exist on jQuery.sticky'); 273 } 274 }; 275 276 $.fn.unstick = function(method) { 277 if (methods[method]) { 278 return methods[method].apply(this, slice.call(arguments, 1)); 279 } else if (typeof method === 'object' || !method ) { 280 return methods.unstick.apply( this, arguments ); 281 } else { 282 $.error('Method ' + method + ' does not exist on jQuery.sticky'); 283 } 284 }; 285 $(function() { 286 setTimeout(scroller, 0); 287 }); 288 }));