1/*! 2 * Theia Sticky Sidebar v1.2.2 3 * https://github.com/WeCodePixels/theia-sticky-sidebar 4 * 5 * Glues your website's sidebars, making them permanently visible while scrolling. 6 * 7 * Copyright 2013-2014 WeCodePixels and other contributors 8 * Released under the MIT license 9 */ 10 11(function($) { 12 $.fn.theiaStickySidebar = function(options) { 13 var defaults = { 14 'containerSelector': '', 15 'additionalMarginTop': 0, 16 'additionalMarginBottom': 0, 17 'updateSidebarHeight': true, 18 'minWidth': 0 19 }; 20 options = $.extend(defaults, options); 21 22 // Validate options 23 options.additionalMarginTop = parseInt(options.additionalMarginTop) || 0; 24 options.additionalMarginBottom = parseInt(options.additionalMarginBottom) || 0; 25 26 // Add CSS 27 $('head').append($('<style>.theiaStickySidebar:after {content: ""; display: table; clear: both;}</style>')); 28 29 this.each(function() { 30 var o = {}; 31 o.sidebar = $(this); 32 33 // Save options 34 o.options = options || {}; 35 36 // Get container 37 o.container = $(o.options.containerSelector); 38 if (o.container.size() == 0) { 39 o.container = o.sidebar.parent(); 40 } 41 42 // Create sticky sidebar 43 o.sidebar.parents().css('-webkit-transform', 'none'); // Fix for WebKit bug - https://code.google.com/p/chromium/issues/detail?id=20574 44 o.sidebar.css({ 45 'position': 'relative', 46 'overflow': 'visible', 47 // The "box-sizing" must be set to "content-box" because we set a fixed height to this element when the sticky
47sidebar has a fixed position. 48 '-webkit-box-sizing': 'border-box', 49 '-moz-box-sizing': 'border-box', 50 'box-sizing': 'border-box' 51 }); 52 53 // Get the sticky sidebar element. If none has been found, then create one. 54 o.stickySidebar = o.sidebar.find('.theiaStickySidebar'); 55 if (o.stickySidebar.length == 0) { 56 o.sidebar.find('script').remove(); // Remove <script> tags, otherwise they will be run again on the next line. 57 o.stickySidebar = $('<div>').addClass('theiaStickySidebar').append(o.sidebar.children()); 58 o.sidebar.append(o.stickySidebar); 59 } 60 61 // Get existing top and bottom margins and paddings 62 o.marginTop = parseInt(o.sidebar.css('margin-top')); 63 o.marginBottom = parseInt(o.sidebar.css('margin-bottom')); 64 o.paddingTop = parseInt(o.sidebar.css('padding-top')); 65 o.paddingBottom = parseInt(o.sidebar.css('padding-bottom')); 66
67 // Add a temporary padding rule to check for collapsable margins. 68 var collapsedTopHeight = o.stickySidebar.offset().top; 69 var collapsedBottomHeight = o.stickySidebar.outerHeight(); 70 o.stickySidebar.css('padding-top', 1); 71 o.stickySidebar.css('padding-bottom', 1); 72 collapsedTopHeight -= o.stickySidebar.offset().top; 73 collapsedBottomHeight = o.stickySidebar.outerHeight() - collapsedBottomHeight - collapsedTopHeight; 74 if (collapsedTopHeight == 0) { 75 o.stickySidebar.css('padding-top', 0); 76 o.stickySidebarPaddingTop = 0; 77 } 78 else { 79 o.stickySidebarPaddingTop = 1; 80 } 81 82 if (collapsedBottomHeight == 0) { 83 o.stickySidebar.css('padding-bottom', 0); 84 o.stickySidebarPaddingBottom = 0; 85 } 86 else { 87 o.stickySidebarPaddingBottom = 1; 88 } 89 90 // We use this to know whether the user is scrolling up or down. 91 o.previousScrollTop = null; 92 93 // Scroll top (value) when the sidebar has fixed position. 94 o.fixedScrollTop = 0; 95 96 // Set sidebar to default values. 97 resetSidebar(); 98 99 o.onScroll = function(o) { 100 // Stop if the sidebar isn't visible. 101 if (!o.stickySidebar.is(":visible")) { 102 return; 103 } 104 105 // Stop if the window is too small. 106 if ($('body').width() < o.options.minWidth) { 107 resetSidebar(); 108 return; 109 } 110 111 // Stop if the sidebar width is larger than the container width (e.g. the theme is responsive and the sidebar is now below the content) 112 if (o.sidebar.outerWidth(true) + 50 > o.container.width()) { 113 resetSidebar(); 114 return; 115 } 116 117 var scrollTop = $(document).scrollTop(); 118 var position = 'static'; 119 120 // If the user has scrolled down enough for the sidebar to be clipped at the top, then we can consider changing its position. 121 if (scrollTop >= o.container.offset().top + (o.paddingTop + o.marginTop - o.options.additionalMarginTop)) { 122 // The top and bottom offsets, used in various calculations. 123 var offsetTop = o.paddingTop + o.marginTop + options.additionalMarginTop; 124 var offsetBottom = o.paddingBottom + o.marginBottom + options.additionalMarginBottom; 125 126 // All top and bottom positions are relative to the window, not to the parent elemnts. 127 var containerTop = o.container.offset().top; 128 var containerBottom = o.container.offset().top + getClearedHeight(o.container); 129 130 // The top and bottom offsets relative to the window screen top (zero) and bottom (window height). 131 var windowOffsetTop = 0 + options.additionalMarginTop; 132 var windowOffsetBottom; 133 134 var sidebarSmallerThanWindow = (o.stickySidebar.outerHeight() + offsetTop + offsetBottom) < $(window).height(); 135 if (sidebarSmallerThanWindow) { 136 windowOffsetBottom = windowOffsetTop + o.stickySidebar.outerHeight(); 137 } 138 else { 139 windowOffsetBottom = $(window).height() - o.marginBottom - o.paddingBottom - options.additionalMarginBottom; 140 } 141 142 var staticLimitTop = containerTop - scrollTop + o.paddingTop + o.marginTop; 143 var staticLimitBottom = containerBottom - scrollTop - o.paddingBottom - o.marginBottom; 144 145 var top = o.stickySidebar.offset().top - scrollTop; 146 var scrollTopDiff = o.previousScrollTop - scrollTop; 147 148 // If the sidebar position is fixed, then it won't move up or down by itself. So, we manually adjust the top coordinate. 149 if (o.stickySidebar.css('position') == 'fixed') { 150 top += scrollTopDiff; 151 } 152 153 if (scrollTopDiff > 0) { // If the user is scrolling up. 154 top = Math.min(top, windowOffsetTop); 155 } 156 else { // If the user is scrolling down. 157 top = Math.max(top, windowOffsetBottom - o.stickySidebar.outerHeight()); 158 } 159 160 top = Math.max(top, staticLimitTop); 161 162 top = Math.min(top, staticLimitBottom - o.stickySidebar.outerHeight()); 163 164 // If the sidebar is the same height as the container, we won't use fixed positioning. 165 var sidebarSameHeightAsContainer = o.container.height() == o.stickySidebar.outerHeight(); 166 167 if (!sidebarSameHeightAsContainer && top == windowOffsetTop) { 168 position = 'fixed'; 169 } 170 else if (!sidebarSameHeightAsContainer && top == windowOffsetBottom - o.stickySidebar.outerHeight()) { 171 position = 'fixed'; 172 } 173 else if (scrollTop + top - o.sidebar.offset().top - o.paddingTop <= options.additionalMarginTop) { 174 position = 'static'; 175 } 176 else { 177 position = 'absolute'; 178 } 179 } 180 181 /*
182 * Performance notice: It's OK to set these CSS values at each resize/scroll, even if they don't change. 183 * It's way slower to first check if the values have changed. 184 */ 185 if (position == 'fixed') { 186 o.stickySidebar.css({ 187 'position': 'fixed', 188 'width': o.sidebar.width(), 189 'top': top, 190 'left': o.sidebar.offset().left + parseInt(o.sidebar.css('padding-left')) 191 }); 192 } 193 else if (position == 'absolute') { 194 var css = {}; 195 196 if (o.stickySidebar.css('position') != 'absolute') { 197 css.position = 'absolute'; 198 css.top = scrollTop + top - o.sidebar.offset().top - o.stickySidebarPaddingTop - o.stickySidebarPaddingBottom; 199 } 200 201 css.width = o.sidebar.width(); 202 css.left = ''; 203 204 o.stickySidebar.css(css); 205 } 206 else if (position == 'static') { 207 resetSidebar(); 208 } 209 210 if (position != 'static') { 211 if (o.options.updateSidebarHeight == true) { 212 o.sidebar.css({ 213 'min-height': o.stickySidebar.outerHeight() + o.stickySidebar.offset().top - o.sidebar.offset().top + o.paddingBottom 214 }); 215 } 216 } 217 218 o.previousScrollTop = scrollTop; 219 }; 220 221 // Initialize the sidebar's position. 222 o.onScroll(o); 223 224 // Recalculate the sidebar's position on every scroll and resize. 225 $(document).scroll(function(o) { 226 return function() { 227 o.onScroll(o); 228 }; 229 }(o)); 230 $(window).resize(function(o) { 231 return function() { 232 o.stickySidebar.css({'position': 'static'}); 233 o.onScroll(o); 234 }; 235 }(o)); 236 237 // Reset the sidebar to its default state 238 function resetSidebar() { 239 o.fixedScrollTop = 0; 240 o.sidebar.css({ 241 'min-height': '1px' 242 }); 243 o.stickySidebar.css({ 244 'position': 'static', 245 'width': '' 246 }); 247 } 248 249 // Get the height of a div as if its floated children were cleared. Note that this function fails if the floats are more than one level deep. 250 function getClearedHeight(e) { 251 var height = e.height(); 252 253 e.children().each(function() { 254 height = Math.max(height, $(this).height()); 255 }); 256 257 return height; 258 } 259 }); 260 } 261})(jQuery); 262 263 jQuery(document).ready(function() { 264 jQuery('.stickyside').theiaStickySidebar({ 265 // Settings 266 additionalMarginTop: 30 267 }); 268 });
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.