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.css({ 44 'position': 'relative', 45 'overflow': 'visible', 46 // The "box-sizing" must be set to "content-box" because we set a fixed height to this element when the sticky
46sidebar has a fixed position. 47 '-webkit-box-sizing': 'border-box', 48 '-moz-box-sizing': 'border-box', 49 'box-sizing': 'border-box' 50 }); 51 52 // Get the sticky sidebar element. If none has been found, then create one. 53 o.stickySidebar = o.sidebar.find('.theiaStickySidebar'); 54 if (o.stickySidebar.length == 0) { 55 o.sidebar.find('script').remove(); // Remove <script> tags, otherwise they will be run again on the next line. 56 o.stickySidebar = $('<div>').addClass('theiaStickySidebar').append(o.sidebar.children()); 57 o.sidebar.append(o.stickySidebar); 58 } 59 60 // Get existing top and bottom margins and paddings 61 o.marginTop = parseInt(o.sidebar.css('margin-top')); 62 o.marginBottom = parseInt(o.sidebar.css('margin-bottom')); 63 o.paddingTop = parseInt(o.sidebar.css('padding-top')); 64 o.paddingBottom = parseInt(o.sidebar.css('padding-bottom')); 65 66 // Add a temporary padding rule to check for collapsable margins. 67 var collapsedTopHeight = o.stickySidebar.offset().top; 68 var collapsedBottomHeight = o.stickySidebar.outerHeight(); 69 o.stickySidebar.css('padding-top', 1); 70 o.stickySidebar.css('padding-bottom', 1); 71 collapsedTopHeight -= o.stickySidebar.offset().top; 72 collapsedBottomHeight = o.stickySidebar.outerHeight() - collapsedBottomHeight - collapsedTopHeight; 73 if (collapsedTopHeight == 0) { 74 o.stickySidebar.css('padding-top', 0); 75 o.stickySidebarPaddingTop = 0; 76 } 77 else { 78 o.stickySidebarPaddingTop = 1; 79 } 80 81 if (collapsedBottomHeight == 0) { 82 o.stickySidebar.css('padding-bottom', 0); 83 o.stickySidebarPaddingBottom = 0; 84 } 85 else { 86 o.stickySidebarPaddingBottom = 1; 87 } 88 89 // We use this to know whether the user is scrolling up or down. 90 o.previousScrollTop = null; 91 92 // Scroll top (value) when the sidebar has fixed position. 93 o.fixedScrollTop = 0; 94 95 // Set sidebar to default values. 96 resetSidebar(); 97 98 o.onScroll = function(o) { 99 // Stop if the sidebar isn't visible. 100 if (!o.stickySidebar.is(":visible")) { 101 return; 102 } 103 104 // Stop if the window is too small. 105 if ($('body').width() < o.options.minWidth) { 106 resetSidebar(); 107 return; 108 } 109 110 // 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) 111 if (o.sidebar.outerWidth(true) + 50 > o.container.width()) { 112 resetSidebar(); 113 return; 114 } 115 116 var scrollTop = $(document).scrollTop(); 117 var position = 'static'; 118 119 // If the user has scrolled down enough for the sidebar to be clipped at the top, then we can consider changing its position. 120 if (scrollTop >= o.container.offset().top + (o.paddingTop + o.marginTop - o.options.additionalMarginTop)) { 121 // The top and bottom offsets, used in various calculations. 122 var offsetTop = o.paddingTop + o.marginTop + options.additionalMarginTop; 123 var offsetBottom = o.paddingBottom + o.marginBottom + options.additionalMarginBottom; 124 125 // All top and bottom positions are relative to the window, not to the parent elemnts. 126 var containerTop = o.container.offset().top; 127 var containerBottom = o.container.offset().top + getClearedHeight(o.container); 128 129 // The top and bottom offsets relative to the window screen top (zero) and bottom (window height). 130 var windowOffsetTop = 0 + options.additionalMarginTop; 131 var windowOffsetBottom; 132 133 var sidebarSmallerThanWindow = (o.stickySidebar.outerHeight() + offsetTop + offsetBottom) < $(window).height(); 134 if (sidebarSmallerThanWindow) { 135 windowOffsetBottom = windowOffsetTop + o.stickySidebar.outerHeight(); 136 } 137 else { 138 windowOffsetBottom = $(window).height() - o.marginBottom - o.paddingBottom - options.additionalMarginBottom; 139 } 140 141 var staticLimitTop = containerTop - scrollTop + o.paddingTop + o.marginTop; 142 var staticLimitBottom = containerBottom - scrollTop - o.paddingBottom - o.marginBottom; 143 144 var top = o.stickySidebar.offset().top - scrollTop; 145 var scrollTopDiff = o.previousScrollTop - scrollTop; 146 147 // If the sidebar position is fixed, then it won't move up or down by itself. So, we manually adjust the top coordinate. 148 if (o.stickySidebar.css('position') == 'fixed') { 149 top += scrollTopDiff; 150 } 151 152 if (scrollTopDiff > 0) { // If the user is scrolling up. 153 top = Math.min(top, windowOffsetTop); 154 } 155 else { // If the user is scrolling down. 156 top = Math.max(top, windowOffsetBottom - o.stickySidebar.outerHeight()); 157 } 158 159 top = Math.max(top, staticLimitTop); 160 161 top = Math.min(top, staticLimitBottom - o.stickySidebar.outerHeight()); 162 163 // If the sidebar is the same height as the container, we won't use fixed positioning. 164 var sidebarSameHeightAsContainer = o.container.height() == o.stickySidebar.outerHeight(); 165 166 if (!sidebarSameHeightAsContainer && top == windowOffsetTop) { 167 position = 'fixed'; 168 } 169 else if (!sidebarSameHeightAsContainer && top == windowOffsetBottom - o.stickySidebar.outerHeight()) { 170 position = 'fixed'; 171 } 172 else if (scrollTop + top - o.sidebar.offset().top - o.paddingTop <= options.additionalMarginTop) { 173 position = 'static'; 174 } 175 else { 176 position = 'absolute'; 177 } 178 } 179 180 /*
181 * Performance notice: It's OK to set these CSS values at each resize/scroll, even if they don't change. 182 * It's way slower to first check if the values have changed. 183 */ 184 if (position == 'fixed') { 185 o.stickySidebar.css({ 186 'position': 'fixed', 187 'width': o.sidebar.width(), 188 'top': top, 189 'left': o.sidebar.offset().left + parseInt(o.sidebar.css('padding-left')) 190 }); 191 } 192 else if (position == 'absolute') { 193 var css = {}; 194 195 if (o.stickySidebar.css('position') != 'absolute') { 196 css.position = 'absolute'; 197 css.top = scrollTop + top - o.sidebar.offset().top - o.stickySidebarPaddingTop - o.stickySidebarPaddingBottom; 198 } 199 200 css.width = o.sidebar.width(); 201 css.left = ''; 202 203 o.stickySidebar.css(css); 204 } 205 else if (position == 'static') { 206 resetSidebar(); 207 } 208 209 if (position != 'static') { 210 if (o.options.updateSidebarHeight == true) { 211 o.sidebar.css({ 212 'min-height': o.stickySidebar.outerHeight() + o.stickySidebar.offset().top - o.sidebar.offset().top + o.paddingBottom 213 }); 214 } 215 } 216 217 o.previousScrollTop = scrollTop; 218 }; 219 220 // Initialize the sidebar's position. 221 o.onScroll(o); 222 223 // Recalculate the sidebar's position on every scroll and resize. 224 $(document).scroll(function(o) { 225 return function() { 226 o.onScroll(o); 227 }; 228 }(o)); 229 $(window).resize(function(o) { 230 return function() { 231 o.stickySidebar.css({'position': 'static'}); 232 o.onScroll(o); 233 }; 234 }(o)); 235 236 // Reset the sidebar to its default state 237 function resetSidebar() { 238 o.fixedScrollTop = 0; 239 o.sidebar.css({ 240 'min-height': '1px' 241 }); 242 o.stickySidebar.css({ 243 'position': 'static', 244 'width': '' 245 }); 246 } 247 248 // 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. 249 function getClearedHeight(e) { 250 var height = e.height(); 251 252 e.children().each(function() { 253 height = Math.max(height, $(this).height()); 254 }); 255 256 return height; 257 } 258 }); 259 } 260})(jQuery);
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.