PageSourceSearch

https://www.biotechcrossing.com/htm/script/theia-sticky-sidebar_20191218033327.js

js biotechcrossing.com collected 2026-09-26 11:56:14 UTC 10,628 bytes, 324 lines download raw bytes

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