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