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