1/*! 2 * Theia Sticky Sidebar v1.6.0 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-2016 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 'disableOnResponsiveLayouts': true, 20 'sidebarBehavior': 'modern' 21 }; 22 options = $.extend(defaults, options); 23 24 // Validate options 25 options.additionalMarginTop = parseInt(options.additionalMarginTop) || 0; 26 options.additionalMarginBottom = parseInt(options.additionalMarginBottom) || 0; 27 28 tryInitOrHookIntoEvents(options, this); 29 30 // Try doing init, otherwise hook into window.resize and document.scroll and try again then. 31 function tryInitOrHookIntoEvents(options, $that) { 32 var success = tryInit(options, $that); 33 34 if (!success) {
35 console.log('TSS: Body width smaller than options.minWidth. Init is delayed.'); 36 37 $(document).scroll(function (options, $that) { 38 return function (evt) { 39 var success = tryInit(options, $that); 40 41 if (success) { 42 $(this).unbind(evt); 43 } 44 }; 45 }(options, $that)); 46 $(window).resize(function (options, $that) { 47 return function (evt) { 48 var success = tryInit(options, $that); 49 50 if (success) { 51 $(this).unbind(evt); 52 } 53 }; 54 }(options, $that)) 55 } 56 } 57 58 // Try doing init if proper conditions are met. 59 function tryInit(options, $that) { 60 if (options.initialized === true) { 61 return true; 62 } 63 64 if ($('body').width() < options.minWidth) { 65 return false; 66 } 67 68 init(options, $that); 69 70 return true; 71 } 72 73 // Init the sticky sidebar(s). 74 function init(options, $that) { 75 options.initialized = true; 76 77 // Add CSS 78 $('head').append($('<style>.theiaStickySidebar:after {content: ""; display: table; clear: both;}</style>')); 79 80 $that.each(function () { 81 var o = {}; 82 83 o.sidebar = $(this); 84 85 // Save options 86 o.options = options || {}; 87 88 // Get container 89 o.container = $(o.options.containerSelector); 90 if (o.container.length == 0) { 91 o.container = o.sidebar.parent(); 92 } 93 94 // Create sticky sidebar 95 o.sidebar.parents().css('-webkit-transform', 'none'); // Fix for WebKit bug - https://code.google.com/p/chromium/issues/detail?id=20574 96 o.sidebar.css({ 97 'position': 'relative', 98 'overflow': 'visible', 99 // The "box-sizing" must be set to "content-box" because we set a fixed height to this element when the sticky
99sidebar has a fixed position. 100 '-webkit-box-sizing': 'border-box', 101 '-moz-box-sizing': 'border-box', 102 'box-sizing': 'border-box' 103 }); 104 105 // Get the sticky sidebar element. If none has been found, then create one. 106 o.stickySidebar = o.sidebar.find('.theiaStickySidebar'); 107 if (o.stickySidebar.length == 0) { 108 // Remove <script> tags, otherwise they will be run again when added to the stickySidebar. 109 var javaScriptMIMETypes = /(?:text|application)\/(?:x-)?(?:javascript|ecmascript)/i; 110 o.sidebar.find('script').filter(function (index, script) { 111 return script.type.length === 0 || script.type.match(javaScriptMIMETypes); 112 }).remove(); 113 114 o.stickySidebar = $('<div>').addClass('theiaStickySidebar').append(o.sidebar.children()); 115 o.sidebar.append(o.stickySidebar); 116 } 117 118 // Get existing top and bottom margins and paddings 119 o.marginBottom = parseInt(o.sidebar.css('margin-bottom')); 120 o.paddingTop = parseInt(o.sidebar.css('padding-top')); 121 o.paddingBottom = parseInt(o.sidebar.css('padding-bottom')); 122
123 // Add a temporary padding rule to check for collapsable margins. 124 var collapsedTopHeight = o.stickySidebar.offset().top; 125 var collapsedBottomHeight = o.stickySidebar.outerHeight(); 126 o.stickySidebar.css('padding-top', 1); 127 o.stickySidebar.css('padding-bottom', 1); 128 collapsedTopHeight -= o.stickySidebar.offset().top; 129 collapsedBottomHeight = o.stickySidebar.outerHeight() - collapsedBottomHeight - collapsedTopHeight; 130 if (collapsedTopHeight == 0) { 131 o.stickySidebar.css('padding-top', 0); 132 o.stickySidebarPaddingTop = 0; 133 } 134 else { 135 o.stickySidebarPaddingTop = 1; 136 } 137 138 if (collapsedBottomHeight == 0) { 139 o.stickySidebar.css('padding-bottom', 0); 140 o.stickySidebarPaddingBottom = 0; 141 } 142 else { 143 o.stickySidebarPaddingBottom = 1; 144 } 145 146 // We use this to know whether the user is scrolling up or down. 147 o.previousScrollTop = null; 148 149 // Scroll top (value) when the sidebar has fixed position. 150 o.fixedScrollTop = 0; 151 152 // Set sidebar to default values. 153 resetSidebar(); 154 155 o.onScroll = function (o) { 156 // Stop if the sidebar isn't visible. 157 if (!o.stickySidebar.is(":visible")) { 158 return; 159 } 160 161 // Stop if the window is too small. 162 if ($('body').width() < o.options.minWidth) { 163 resetSidebar(); 164 return; 165 } 166 167 // 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) 168 if (o.options.disableOnResponsiveLayouts) { 169 var sidebarWidth = o.sidebar.outerWidth(o.sidebar.css('float') == 'none'); 170 171 if (sidebarWidth + 50 > o.container.width()) { 172 resetSidebar(); 173 return; 174 } 175 } 176 177 var scrollTop = $(document).scrollTop(); 178 var position = 'static'; 179 180 // If the user has scrolled down enough for the sidebar to be clipped at the top, then we can consider changing its position. 181 if (scrollTop >= o.sidebar.offset().top + (o.paddingTop - o.options.additionalMarginTop)) { 182 // The top and bottom offsets, used in various calculations. 183 var offsetTop = o.paddingTop + options.additionalMarginTop; 184 var offsetBottom = o.paddingBottom + o.marginBottom + options.additionalMarginBottom; 185 186 // All top and bottom positions are relative to the window, not to the parent elemnts. 187 var containerTop = o.sidebar.offset().top; 188 var containerBottom = o.sidebar.offset().top + getClearedHeight(o.container); 189 190 // The top and bottom offsets relative to the window screen top (zero) and bottom (window height). 191 var windowOffsetTop = 0 + options.additionalMarginTop; 192 var windowOffsetBottom; 193 194 var sidebarSmallerThanWindow = (o.stickySidebar.outerHeight() + offsetTop + offsetBottom) < $(window).height(); 195 if (sidebarSmallerThanWindow) { 196 windowOffsetBottom = windowOffsetTop + o.stickySidebar.outerHeight(); 197 } 198 else { 199 windowOffsetBottom = $(window).height() - o.marginBottom - o.paddingBottom - options.additionalMarginBottom; 200 } 201 202 var staticLimitTop = containerTop - scrollTop + o.paddingTop; 203 var staticLimitBottom = containerBottom - scrollTop - o.paddingBottom - o.marginBottom; 204 205 var top = o.stickySidebar.offset().top - scrollTop; 206 var scrollTopDiff = o.previousScrollTop - scrollTop; 207 208 // If the sidebar position is fixed, then it won't move up or down by itself. So, we manually adjust the top coordinate. 209 if (o.stickySidebar.css('position') == 'fixed') { 210 if (o.options.sidebarBehavior == 'modern') { 211 top += scrollTopDiff; 212 } 213 } 214 215 if (o.options.sidebarBehavior == 'stick-to-top') { 216 top = options.additionalMarginTop; 217 } 218 219 if (o.options.sidebarBehavior == 'stick-to-bottom') { 220 top = windowOffsetBottom - o.stickySidebar.outerHeight(); 221 } 222 223 if (scrollTopDiff > 0) { // If the user is scrolling up. 224 top = Math.min(top, windowOffsetTop); 225 } 226 else { // If the user is scrolling down. 227 top = Math.max(top, windowOffsetBottom - o.stickySidebar.outerHeight()); 228 } 229 230 top = Math.max(top, staticLimitTop); 231 232 top = Math.min(top, staticLimitBottom - o.stickySidebar.outerHeight()); 233 234 // If the sidebar is the same height as the container, we won't use fixed positioning. 235 var sidebarSameHeightAsContainer = o.container.height() == o.stickySidebar.outerHeight(); 236 237 if (!sidebarSameHeightAsContainer && top == windowOffsetTop) { 238 position = 'fixed'; 239 } 240 else if (!sidebarSameHeightAsContainer && top == windowOffsetBottom - o.stickySidebar.outerHeight()) { 241 position = 'fixed'; 242 } 243 else if (scrollTop + top - o.sidebar.offset().top - o.paddingTop <= options.additionalMarginTop) { 244 // Stuck to the top of the page. No special behavior. 245 position = 'static'; 246 } 247 else { 248 // Stuck to the bottom of the page. 249 position = 'absolute'; 250 } 251 } 252 253 /*
254 * Performance notice: It's OK to set these CSS values at each resize/scroll, even if they don't change. 255 * It's way slower to first check if the values have changed. 256 */ 257 if (position == 'fixed') { 258 var scrollLeft = $(document).scrollLeft(); 259 260 o.stickySidebar.css({ 261 'position': 'fixed', 262 'width': getWidthForObject(o.stickySidebar) + 'px', 263 'transform': 'translateY(' + top + 'px)', 264 'left': (o.sidebar.offset().left + parseInt(o.sidebar.css('padding-left')) - scrollLeft) + 'px', 265 'top': '0px' 266 }); 267 } 268 else if (position == 'absolute') { 269 var css = {}; 270 271 if (o.stickySidebar.css('position') != 'absolute') { 272 css.position = 'absolute'; 273 css.transform = 'translateY(' + (scrollTop + top - o.sidebar.offset().top - o.stickySidebarPaddingTop - o.stickySidebarPaddingBottom) + 'px)'; 274 css.top = '0px'; 275 } 276 277 css.width = getWidthForObject(o.stickySidebar) + 'px'; 278 css.left = ''; 279 280 o.stickySidebar.css(css); 281 } 282 else if (position == 'static') { 283 resetSidebar(); 284 } 285 286 if (position != 'static') { 287 if (o.options.updateSidebarHeight == true) { 288 o.sidebar.css({ 289 'min-height': o.stickySidebar.outerHeight() + o.stickySidebar.offset().top - o.sidebar.offset().top + o.paddingBottom 290 }); 291 } 292 } 293 294 o.previousScrollTop = scrollTop; 295 }; 296 297 // Initialize the sidebar's position. 298 o.onScroll(o); 299 300 // Recalculate the sidebar's position on every scroll and resize. 301 $(document).scroll(function (o) { 302 return function () { 303 o.onScroll(o); 304 }; 305 }(o)); 306 $(window).resize(function (o) { 307 return function () { 308 o.stickySidebar.css({'position': 'static'}); 309 o.onScroll(o); 310 }; 311 }(o)); 312 313 // Recalculate the sidebar's position every time the sidebar changes its size. 314 if (typeof ResizeSensor !== 'undefined') { 315 new ResizeSensor(o.stickySidebar[0], function (o) { 316 return function () { 317 o.onScroll(o); 318 }; 319 }(o)); 320 } 321 322 // Reset the sidebar to its default state 323 function resetSidebar() { 324 o.fixedScrollTop = 0; 325 o.sidebar.css({ 326 'min-height': '1px' 327 }); 328 o.stickySidebar.css({ 329 'position': 'static', 330 'width': '', 331 'transform': 'none' 332 }); 333 } 334 335 // 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. 336 function getClearedHeight(e) { 337 var height = e.height(); 338 339 e.children().each(function () { 340 height = Math.max(height, $(this).height()); 341 }); 342 343 return height; 344 } 345 }); 346 } 347 348 function getWidthForObject(object) { 349 var width; 350 351 try { 352 width = object[0].getBoundingClientRect().width; 353 } 354 catch (err) { 355 } 356 357 if (typeof width === "undefined") { 358 width = object.width(); 359 } 360 361 return width; 362 } 363 } 364})(jQuery); 365 366//# sourceMappingURL=maps/theia-sticky-sidebar.js.map
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.