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