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 o.windowWidth = window.innerWidth; 175 o.cachedOffsetTop = o.sidebar.offset().top; 176 setInterval(function(){ 177 o.cachedOffsetTop = o.sidebar.offset().top; 178 }, 1000); 179 o.prevPosition = ''; 180 // Nectar addition end 181 182 // We use this to know whether the user is scrolling up or down. 183 o.previousScrollTop = null; 184 185 // Scroll top (value) when the sidebar has fixed position. 186 o.fixedScrollTop = 0; 187 188 // Set sidebar to default values. 189 resetSidebar(); 190 191 o.onScroll = function (o) { 192 193 // Stop if the sidebar isn't visible. 194 //nectar addition of the ocm and search 195 if (!o.stickySidebarVisible || $('.ocm-effect-wrap.material-ocm-open').length > 0 ) { 196 return; 197 } 198 199 // Stop if the window is too small. 200 /*if ($('body').width() < o.options.minWidth) { 201 resetSidebar(); 202 return; 203 } */ 204 205 // 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) 206 if (o.options.disableOnResponsiveLayouts && o.windowWidth < 1000) { 207 // Nectar addition. 208 resetSidebar(); 209 return; 210 // Nectar addition end. 211 } 212 213 var scrollTop = nectarStickyState.scrollTop; 214 var position = 'static'; 215 216 217 218 // If the user has scrolled down enough for the sidebar to be clipped at the top, then we can consider changing its position. 219 220 if (scrollTop >= o.cachedOffsetTop + (o.paddingTop - o.options.additionalMarginTop)) { 221 222 var cachedOuterHeight = o.stickySidebar.outerHeight(); 223 224 // The top and bottom offsets, used in various calculations. 225 var offsetTop = o.paddingTop + options.additionalMarginTop; 226 var offsetBottom = o.paddingBottom + o.marginBottom + options.additionalMarginBottom; 227 228 // All top and bottom positions are relative to the window, not to the parent elemnts. 229 var containerHeight = getClearedHeight(o.container); 230 231 var containerTop = o.cachedOffsetTop; 232 var containerBottom = o.cachedOffsetTop + containerHeight; 233 234 // The top and bottom offsets relative to the window screen top (zero) and bottom (window height). 235 var windowOffsetTop = 0 + options.additionalMarginTop; 236 var windowOffsetBottom; 237 238 239 // Nectar addition conditional 240 if( containerHeight > cachedOuterHeight + options.additionalMarginTop ) { 241 242 243 var sidebarSmallerThanWindow = (cachedOuterHeight + offsetTop + offsetBottom) < o.windowHeight; 244 if (sidebarSmallerThanWindow) { 245 windowOffsetBottom = windowOffsetTop + cachedOuterHeight; 246 } 247 else { 248 windowOffsetBottom = o.windowHeight - o.marginBottom - o.paddingBottom - options.additionalMarginBottom; 249 } 250 251 var staticLimitTop = containerTop - scrollTop + o.paddingTop; 252 var staticLimitBottom = containerBottom - scrollTop - o.paddingBottom - o.marginBottom; 253 254 var top = o.stickySidebar.offset().top - scrollTop; 255 var scrollTopDiff = o.previousScrollTop - scrollTop; 256 257 // If the sidebar position is fixed, then it won't move up or down by itself. So, we manually adjust the top coordinate. 258 if (o.stickySidebar.css('position') == 'fixed') { 259 if (o.options.sidebarBehavior == 'modern') { 260 top += scrollTopDiff; 261 } 262 } 263 264 if (o.options.sidebarBehavior == 'stick-to-top') { 265 top = options.additionalMarginTop; 266 } 267 268 if (o.options.sidebarBehavior == 'stick-to-bottom') { 269 top = windowOffsetBottom - cachedOuterHeight; 270 } 271 272 if (scrollTopDiff > 0) { // If the user is scrolling up. 273 top = Math.min(top, windowOffsetTop); 274 } 275 else { // If the user is scrolling down. 276 top = Math.max(top, windowOffsetBottom - cachedOuterHeight); 277 } 278 279 top = Math.max(top, staticLimitTop); 280 281 top = Math.min(top, staticLimitBottom - cachedOuterHeight); 282 283 // If the sidebar is the same height as the container, we won't use fixed positioning. 284 var sidebarSameHeightAsContainer = o.container.height() == cachedOuterHeight; 285 286 if (!sidebarSameHeightAsContainer && top == windowOffsetTop) { 287 position = 'fixed'; 288 } 289 else if (!sidebarSameHeightAsContainer && top == windowOffsetBottom - cachedOuterHeight) { 290 position = 'fixed'; 291 } 292 else if (scrollTop + top - o.cachedOffsetTop - o.paddingTop <= options.additionalMarginTop ) { 293 // Stuck to the top of the page. No special behavior. 294 position = 'static'; 295 } 296 else { 297 // Stuck to the bottom of the page. 298 position = 'absolute'; 299 } 300 301 }// Nectar addition conditional end. 302 303 304 305 } 306 307 /*
308 * Performance notice: It's OK to set these CSS values at each resize/scroll, even if they don't change. 309 * It's way slower to first check if the values have changed. 310 */ 311 if (position == 'fixed' && o.prevPosition != 'fixed') { 312 var scrollLeft = nectarStickyState.scrollLeft; 313 314 o.stickySidebar.css({ 315 'position': 'fixed', 316 'width': getWidthForObject(o.sidebar) + 'px', 317 'transform': 'translateY(' + top + 'px)', 318 'left': (o.sidebar.offset().left + parseInt(o.sidebar.css('padding-left')) - scrollLeft) + 'px', 319 'top': '0px' 320 }); 321 } 322 else if (position == 'absolute' && o.prevPosition != 'absolute') { 323 var css = {}; 324 325 if (o.stickySidebar.css('position') != 'absolute') { 326 css.position = 'absolute'; 327 css.transform = 'translateY(' + (scrollTop + top - o.sidebar.offset().top - o.stickySidebarPaddingTop - o.stickySidebarPaddingBottom) + 'px)'; 328 css.top = '0px'; 329 } 330 331 css.width = getWidthForObject(o.sidebar) + 'px'; 332 css.left = ''; 333 334 o.stickySidebar.css(css); 335 } 336 else if (position == 'static' && o.prevPosition != 'static') { 337 338 resetSidebar(); 339 } 340 341 if (position != 'static') { 342 if (o.options.updateSidebarHeight == true) { 343 o.sidebar.css({ 344 'min-height': o.stickySidebar.outerHeight() + o.stickySidebar.offset().top - o.sidebar.offset().top + o.paddingBottom 345 }); 346 } 347 } 348 349 o.prevPosition = position; 350 o.previousScrollTop = scrollTop; 351 }; 352 353 // Initialize the sidebar's position. 354 o.onScroll(o); 355 356 // Recalculate the sidebar's position on every scroll and resize. 357 $(document).on('scroll.' + o.options.namespace, function (o) { 358 return function () { 359 o.onScroll(o); 360 }; 361 }(o)); 362 // nectar addition end 363 $(window).on('load.' + o.options.namespace, function (o) { 364 o.stickySidebarVisible = o.stickySidebar.is(":visible"); 365 o.windowHeight = $(window).height(); 366 o.windowWidth = window.innerWidth; 367 o.cachedOffsetTop = o.sidebar.offset().top; 368 }(o)); 369 // nectar addition end 370 $(window).on('resize.' + o.options.namespace, function (o) { 371 return function () { 372 // nectar addition end 373 o.stickySidebarVisible = o.stickySidebar.is(":visible"); 374 o.paddingTop = parseInt(o.sidebar.css('padding-top')); 375 o.paddingBottom = parseInt(o.sidebar.css('padding-bottom')); 376 o.windowHeight = $(window).height(); 377 o.windowWidth = window.innerWidth; 378 o.cachedOffsetTop = o.sidebar.offset().top; 379 // nectar addition end 380 o.prevPosition = ''; 381 o.stickySidebar.css({'position': 'static'}); 382 o.onScroll(o); 383 }; 384 }(o)); 385 386 // Recalculate the sidebar's position every time the sidebar changes its size. 387 if (typeof ResizeSensor !== 'undefined') { 388 new ResizeSensor(o.stickySidebar[0], function (o) { 389 return function () { 390 o.onScroll(o); 391 }; 392 }(o)); 393 } 394 395 // Reset the sidebar to its default state 396 function resetSidebar() { 397 o.fixedScrollTop = 0; 398 o.sidebar.css({ 399 'min-height': '1px' 400 }); 401 o.stickySidebar.css({ 402 'position': 'static', 403 'width': '', 404 'transform': 'none' 405 }); 406 } 407 408 // 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. 409 function getClearedHeight(e) { 410 var height = e.height(); 411 412 e.children().each(function () { 413 height = Math.max(height, $(this).height()); 414 }); 415 416 return height; 417 } 418 }); 419 } 420 421 function getWidthForObject(object) { 422 var width; 423 /* nectar addition - get width with padding */ 424 width = object.width(); 425 return width; 426 427 try { 428 width = object[0].getBoundingClientRect().width; 429 } 430 catch (err) { 431 } 432 433 if (typeof width === "undefined") { 434 width = object.width(); 435 } 436 437 return width; 438 } 439 440 return this; 441 } 442})(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.